mirror of https://github.com/Squidex/squidex.git
125 changed files with 1308 additions and 186 deletions
@ -0,0 +1,77 @@ |
|||||
|
// ==========================================================================
|
||||
|
// MongoPersistedGrantStore.cs
|
||||
|
// PinkParrot Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) PinkParrot Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using IdentityServer4.Models; |
||||
|
using IdentityServer4.Stores; |
||||
|
using MongoDB.Bson.Serialization; |
||||
|
using MongoDB.Driver; |
||||
|
using PinkParrot.Store.MongoDb.Utils; |
||||
|
|
||||
|
namespace PinkParrot.Store.MongoDb.Infrastructure |
||||
|
{ |
||||
|
public class MongoPersistedGrantStore : MongoRepositoryBase<PersistedGrant>, IPersistedGrantStore |
||||
|
{ |
||||
|
static MongoPersistedGrantStore() |
||||
|
{ |
||||
|
BsonClassMap.RegisterClassMap<PersistedGrant>(map => |
||||
|
{ |
||||
|
map.AutoMap(); |
||||
|
map.MapIdProperty(x => x.Key); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
public MongoPersistedGrantStore(IMongoDatabase database) |
||||
|
: base(database) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
protected override string CollectionName() |
||||
|
{ |
||||
|
return "PersistedGrants"; |
||||
|
} |
||||
|
|
||||
|
protected override Task SetupCollectionAsync(IMongoCollection<PersistedGrant> collection) |
||||
|
{ |
||||
|
return Task.WhenAll( |
||||
|
collection.Indexes.CreateOneAsync(IndexKeys.Ascending(x => x.ClientId)), |
||||
|
collection.Indexes.CreateOneAsync(IndexKeys.Ascending(x => x.SubjectId))); |
||||
|
} |
||||
|
|
||||
|
public Task StoreAsync(PersistedGrant grant) |
||||
|
{ |
||||
|
return Collection.ReplaceOneAsync(x => x.Key == grant.Key, grant, new UpdateOptions { IsUpsert = true }); |
||||
|
} |
||||
|
|
||||
|
public Task<IEnumerable<PersistedGrant>> GetAllAsync(string subjectId) |
||||
|
{ |
||||
|
return Collection.Find(x => x.SubjectId == subjectId).ToListAsync().ContinueWith(x => (IEnumerable<PersistedGrant>)x.Result); |
||||
|
} |
||||
|
|
||||
|
public Task<PersistedGrant> GetAsync(string key) |
||||
|
{ |
||||
|
return Collection.Find(x => x.Key == key).FirstOrDefaultAsync(); |
||||
|
} |
||||
|
|
||||
|
public Task RemoveAllAsync(string subjectId, string clientId, string type) |
||||
|
{ |
||||
|
return Collection.DeleteManyAsync(x => x.SubjectId == subjectId && x.ClientId == clientId && x.Type == type); |
||||
|
} |
||||
|
|
||||
|
public Task RemoveAllAsync(string subjectId, string clientId) |
||||
|
{ |
||||
|
return Collection.DeleteManyAsync(x => x.SubjectId == subjectId && x.ClientId == clientId); |
||||
|
} |
||||
|
|
||||
|
public Task RemoveAsync(string key) |
||||
|
{ |
||||
|
return Collection.DeleteManyAsync(x => x.Key == key); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,14 +1,13 @@ |
|||||
// ==========================================================================
|
// ==========================================================================
|
||||
// MongoDbOptions.cs
|
// MyMongoDbOptions.cs
|
||||
// PinkParrot Headless CMS
|
// PinkParrot Headless CMS
|
||||
// ==========================================================================
|
// ==========================================================================
|
||||
// Copyright (c) PinkParrot Group
|
// Copyright (c) PinkParrot Group
|
||||
// All rights reserved.
|
// All rights reserved.
|
||||
// ==========================================================================
|
// ==========================================================================
|
||||
|
|
||||
namespace PinkParrot.Store.MongoDb |
namespace PinkParrot.Store.MongoDb |
||||
{ |
{ |
||||
public class MongoDbOptions |
public class MyMongoDbOptions |
||||
{ |
{ |
||||
public string ConnectionString { get; set; } |
public string ConnectionString { get; set; } |
||||
|
|
||||
@ -0,0 +1,30 @@ |
|||||
|
{ |
||||
|
// Controls if the editor shows reference information for the modes that support it |
||||
|
"editor.referenceInfos": false, |
||||
|
|
||||
|
// When opening a file, `editor.tabSize` and `editor.insertSpaces` will be detected based on the file contents. |
||||
|
"editor.detectIndentation": false, |
||||
|
|
||||
|
// Typescript version from local package to be consistent |
||||
|
"typescript.tsdk": "node_modules/typescript/lib", |
||||
|
|
||||
|
// Configure glob patterns for excluding files and folders. |
||||
|
"files.exclude": { |
||||
|
"_test-output": true, |
||||
|
"**/node_modules": true, |
||||
|
"**/artifacts": true, |
||||
|
"**/build": true, |
||||
|
"**/out": true, |
||||
|
"**/obj": true, |
||||
|
"**/bin": true, |
||||
|
"**/*.lock.json": true, |
||||
|
"**/*.bat": true, |
||||
|
"**/*.sln": true, |
||||
|
"**/*.sln.DotSettings": true, |
||||
|
"**/*.user": true, |
||||
|
"**/*.xproj": true, |
||||
|
"**/*.gitattributes": true, |
||||
|
".vs:": true, |
||||
|
".vscode:": true |
||||
|
} |
||||
|
} |
||||
@ -1,14 +1,13 @@ |
|||||
// ==========================================================================
|
// ==========================================================================
|
||||
// EventStoreOptions.cs
|
// MyEventStoreOptions.cs
|
||||
// PinkParrot Headless CMS
|
// PinkParrot Headless CMS
|
||||
// ==========================================================================
|
// ==========================================================================
|
||||
// Copyright (c) PinkParrot Group
|
// Copyright (c) PinkParrot Group
|
||||
// All rights reserved.
|
// All rights reserved.
|
||||
// ==========================================================================
|
// ==========================================================================
|
||||
|
namespace PinkParrot.Configurations.EventStore |
||||
namespace PinkParrot.Configurations |
|
||||
{ |
{ |
||||
public sealed class EventStoreOptions |
public sealed class MyEventStoreOptions |
||||
{ |
{ |
||||
public string IPAddress { get; set; } |
public string IPAddress { get; set; } |
||||
|
|
||||
Binary file not shown.
@ -0,0 +1,84 @@ |
|||||
|
// ==========================================================================
|
||||
|
// IdentityDependencies.cs
|
||||
|
// PinkParrot Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) PinkParrot Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Collections.Generic; |
||||
|
using System.IO; |
||||
|
using System.Security.Cryptography.X509Certificates; |
||||
|
using IdentityServer4.Models; |
||||
|
using Microsoft.AspNetCore.Hosting; |
||||
|
using Microsoft.AspNetCore.Identity.MongoDB; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.IdentityModel.Tokens; |
||||
|
|
||||
|
namespace PinkParrot.Configurations.Identity |
||||
|
{ |
||||
|
public static class IdentityServices |
||||
|
{ |
||||
|
public static IServiceCollection AddMyIdentityServer(this IServiceCollection services, IHostingEnvironment env) |
||||
|
{ |
||||
|
var certPath = Path.Combine(env.ContentRootPath, "Configurations", "Identity", "Cert", "IdentityCert.pfx"); |
||||
|
|
||||
|
var certificate = new X509Certificate2(certPath, "password"); |
||||
|
|
||||
|
services.AddIdentityServer() |
||||
|
.SetSigningCredential(certificate) |
||||
|
.AddInMemoryScopes(GetScopes()) |
||||
|
.AddInMemoryClients(GetClients()) |
||||
|
.AddAspNetIdentity<IdentityUser>(); |
||||
|
|
||||
|
return services; |
||||
|
} |
||||
|
|
||||
|
public static IServiceCollection AddMyIdentity(this IServiceCollection services) |
||||
|
{ |
||||
|
services.AddIdentity<IdentityUser, IdentityRole>() |
||||
|
.AddDefaultTokenProviders(); |
||||
|
|
||||
|
return services; |
||||
|
} |
||||
|
|
||||
|
public static IEnumerable<Scope> GetScopes() |
||||
|
{ |
||||
|
return new List<Scope> |
||||
|
{ |
||||
|
StandardScopes.OpenId, |
||||
|
StandardScopes.Profile, |
||||
|
|
||||
|
new Scope |
||||
|
{ |
||||
|
Name = "api1", |
||||
|
Description = "My API" |
||||
|
} |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
public static IEnumerable<Client> GetClients() |
||||
|
{ |
||||
|
return new List<Client> |
||||
|
{ |
||||
|
new Client |
||||
|
{ |
||||
|
ClientId = "management-portal", |
||||
|
ClientName = "MVC Client", |
||||
|
RedirectUris = new List<string> |
||||
|
{ |
||||
|
"http://localhost:5000/account/client-silent", |
||||
|
"http://localhost:5000/account/client-popup" |
||||
|
}, |
||||
|
AllowedGrantTypes = GrantTypes.Implicit, |
||||
|
AllowedScopes = new List<string> |
||||
|
{ |
||||
|
StandardScopes.OpenId.Name, |
||||
|
StandardScopes.Profile.Name |
||||
|
}, |
||||
|
RequireConsent = false |
||||
|
} |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,106 @@ |
|||||
|
// ==========================================================================
|
||||
|
// IdentityUsage.cs
|
||||
|
// PinkParrot Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) PinkParrot Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.AspNetCore.Builder; |
||||
|
using Microsoft.AspNetCore.Identity; |
||||
|
using Microsoft.AspNetCore.Identity.MongoDB; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
|
||||
|
// ReSharper disable InvertIf
|
||||
|
|
||||
|
namespace PinkParrot.Configurations.Identity |
||||
|
{ |
||||
|
public static class IdentityUsage |
||||
|
{ |
||||
|
public static IApplicationBuilder UseMyIdentity(this IApplicationBuilder app) |
||||
|
{ |
||||
|
app.UseIdentity(); |
||||
|
|
||||
|
app.UseCookieAuthentication(new CookieAuthenticationOptions |
||||
|
{ |
||||
|
AuthenticationScheme = "Cookies" |
||||
|
}); |
||||
|
|
||||
|
return app; |
||||
|
} |
||||
|
|
||||
|
public static IApplicationBuilder UseMyIdentityServer(this IApplicationBuilder app) |
||||
|
{ |
||||
|
app.UseIdentityServer(); |
||||
|
|
||||
|
return app; |
||||
|
} |
||||
|
|
||||
|
public static IApplicationBuilder UseMyDefaultUser(this IApplicationBuilder app) |
||||
|
{ |
||||
|
var options = app.ApplicationServices.GetService<IOptions<MyIdentityOptions>>().Value; |
||||
|
|
||||
|
var username = options.DefaultUsername; |
||||
|
var userManager = app.ApplicationServices.GetService<UserManager<IdentityUser>>(); |
||||
|
|
||||
|
if (!string.IsNullOrWhiteSpace(options.DefaultUsername) && |
||||
|
!string.IsNullOrWhiteSpace(options.DefaultPassword)) |
||||
|
{ |
||||
|
Task.Run(async () => |
||||
|
{ |
||||
|
if (userManager.SupportsQueryableUsers && !userManager.Users.Any()) |
||||
|
{ |
||||
|
var user = new IdentityUser { UserName = username, Email = username, EmailConfirmed = true }; |
||||
|
|
||||
|
await userManager.CreateAsync(user, options.DefaultPassword); |
||||
|
} |
||||
|
}).Wait(); |
||||
|
} |
||||
|
|
||||
|
return app; |
||||
|
} |
||||
|
|
||||
|
public static IApplicationBuilder UseMyGoogleAuthentication(this IApplicationBuilder app) |
||||
|
{ |
||||
|
var options = app.ApplicationServices.GetService<IOptions<MyIdentityOptions>>().Value; |
||||
|
|
||||
|
if (!string.IsNullOrWhiteSpace(options.GoogleClient) && |
||||
|
!string.IsNullOrWhiteSpace(options.GoogleSecret)) |
||||
|
{ |
||||
|
var googleOptions = |
||||
|
new GoogleOptions |
||||
|
{ |
||||
|
ClientId = options.GoogleClient, |
||||
|
ClientSecret = options.GoogleSecret |
||||
|
}; |
||||
|
|
||||
|
app.UseGoogleAuthentication(googleOptions); |
||||
|
} |
||||
|
|
||||
|
return app; |
||||
|
} |
||||
|
|
||||
|
public static IApplicationBuilder UseMyApiProtection(this IApplicationBuilder app) |
||||
|
{ |
||||
|
var options = app.ApplicationServices.GetService<IOptions<MyIdentityOptions>>().Value; |
||||
|
|
||||
|
if (!string.IsNullOrWhiteSpace(options.BaseUrl)) |
||||
|
{ |
||||
|
app.Map("/api", api => |
||||
|
{ |
||||
|
api.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions |
||||
|
{ |
||||
|
Authority = options.BaseUrl, |
||||
|
ScopeName = "api", |
||||
|
RequireHttpsMetadata = options.RequiresHttps |
||||
|
}); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
return app; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,17 +1,24 @@ |
|||||
// ==========================================================================
|
// ==========================================================================
|
||||
// IdentityOptions.cs
|
// MyIdentityOptions.cs
|
||||
// PinkParrot Headless CMS
|
// PinkParrot Headless CMS
|
||||
// ==========================================================================
|
// ==========================================================================
|
||||
// Copyright (c) PinkParrot Group
|
// Copyright (c) PinkParrot Group
|
||||
// All rights reserved.
|
// All rights reserved.
|
||||
// ==========================================================================
|
// ==========================================================================
|
||||
|
namespace PinkParrot.Configurations.Identity |
||||
namespace PinkParrot.Configurations |
|
||||
{ |
{ |
||||
public sealed class IdentityOptions |
public sealed class MyIdentityOptions |
||||
{ |
{ |
||||
public string DefaultUsername { get; set; } |
public string DefaultUsername { get; set; } |
||||
|
|
||||
public string DefaultPassword { get; set; } |
public string DefaultPassword { get; set; } |
||||
|
|
||||
|
public string GoogleClient { get; set; } |
||||
|
|
||||
|
public string GoogleSecret { get; set; } |
||||
|
|
||||
|
public string BaseUrl { get; set; } |
||||
|
|
||||
|
public bool RequiresHttps { get; set; } |
||||
} |
} |
||||
} |
} |
||||
@ -1,43 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// IdentityUsage.cs
|
|
||||
// PinkParrot Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) PinkParrot Group
|
|
||||
// All rights reserved.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System.Linq; |
|
||||
using System.Threading.Tasks; |
|
||||
using Microsoft.AspNetCore.Builder; |
|
||||
using Microsoft.AspNetCore.Identity; |
|
||||
using Microsoft.AspNetCore.Identity.MongoDB; |
|
||||
using Microsoft.Extensions.DependencyInjection; |
|
||||
using Microsoft.Extensions.Options; |
|
||||
|
|
||||
namespace PinkParrot.Configurations |
|
||||
{ |
|
||||
public static class IdentityUsage |
|
||||
{ |
|
||||
public static void UseDefaultUser(this IApplicationBuilder app) |
|
||||
{ |
|
||||
var options = app.ApplicationServices.GetService<IOptions<IdentityOptions>>().Value; |
|
||||
|
|
||||
var username = options.DefaultUsername; |
|
||||
var userManager = app.ApplicationServices.GetService<UserManager<IdentityUser>>(); |
|
||||
|
|
||||
if (!string.IsNullOrWhiteSpace(options.DefaultUsername) && |
|
||||
!string.IsNullOrWhiteSpace(options.DefaultPassword)) |
|
||||
{ |
|
||||
Task.Run(async () => |
|
||||
{ |
|
||||
if (userManager.SupportsQueryableUsers && !userManager.Users.Any()) |
|
||||
{ |
|
||||
var user = new IdentityUser { UserName = username, Email = username, EmailConfirmed = true }; |
|
||||
|
|
||||
await userManager.CreateAsync(user, options.DefaultPassword); |
|
||||
} |
|
||||
}).Wait(); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,21 @@ |
|||||
|
// ==========================================================================
|
||||
|
// WebDependencies.cs
|
||||
|
// PinkParrot Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) PinkParrot Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using PinkParrot.Configurations.Domain; |
||||
|
|
||||
|
namespace PinkParrot.Configurations.Web |
||||
|
{ |
||||
|
public static class WebDependencies |
||||
|
{ |
||||
|
public static void AddMyMvc(this IServiceCollection services) |
||||
|
{ |
||||
|
services.AddMvc().AddMySerializers(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,23 @@ |
|||||
|
// ==========================================================================
|
||||
|
// WebpackServices.cs
|
||||
|
// PinkParrot Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) PinkParrot Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using PinkParrot.Pipeline; |
||||
|
|
||||
|
namespace PinkParrot.Configurations.Web |
||||
|
{ |
||||
|
public static class WebpackServices |
||||
|
{ |
||||
|
public static IServiceCollection AddWebpackBuilder(this IServiceCollection services) |
||||
|
{ |
||||
|
services.AddSingleton<WebpackRunner>(); |
||||
|
|
||||
|
return services; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,142 @@ |
|||||
|
// ==========================================================================
|
||||
|
// AccountController.cs
|
||||
|
// PinkParrot Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) PinkParrot Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Linq; |
||||
|
using System.Security.Claims; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.AspNetCore.Authorization; |
||||
|
using Microsoft.AspNetCore.Identity; |
||||
|
using Microsoft.AspNetCore.Identity.MongoDB; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
|
||||
|
// ReSharper disable ConvertIfStatementToReturnStatement
|
||||
|
|
||||
|
namespace PinkParrot.Modules.UI.Account |
||||
|
{ |
||||
|
public sealed class AccountController : Controller |
||||
|
{ |
||||
|
private readonly SignInManager<IdentityUser> signInManager; |
||||
|
private readonly UserManager<IdentityUser> userManager; |
||||
|
|
||||
|
public AccountController(SignInManager<IdentityUser> signInManager, UserManager<IdentityUser> userManager) |
||||
|
{ |
||||
|
this.signInManager = signInManager; |
||||
|
this.userManager = userManager; |
||||
|
} |
||||
|
|
||||
|
[Authorize] |
||||
|
[HttpGet] |
||||
|
[Route("account/forbidden")] |
||||
|
public IActionResult Forbidden() |
||||
|
{ |
||||
|
return View(); |
||||
|
} |
||||
|
|
||||
|
[HttpGet] |
||||
|
[Route("account/client-silent/")] |
||||
|
public IActionResult ClientSilent() |
||||
|
{ |
||||
|
return View(); |
||||
|
} |
||||
|
|
||||
|
[HttpGet] |
||||
|
[Route("account/client-popup/")] |
||||
|
public IActionResult ClientPopup() |
||||
|
{ |
||||
|
return View(); |
||||
|
} |
||||
|
|
||||
|
[HttpGet] |
||||
|
[Route("account/login/")] |
||||
|
public IActionResult Login(string returnUrl = null) |
||||
|
{ |
||||
|
var providers = |
||||
|
signInManager.GetExternalAuthenticationSchemes() |
||||
|
.Select(x => new ExternalProvider(x.AuthenticationScheme, x.DisplayName)) |
||||
|
.ToList(); |
||||
|
|
||||
|
return View(new LoginVM { ExternalProviders = providers, ReturnUrl = returnUrl }); |
||||
|
} |
||||
|
|
||||
|
[HttpPost] |
||||
|
[Route("account/external/")] |
||||
|
public IActionResult External(string provider, string returnUrl = null) |
||||
|
{ |
||||
|
var properties = |
||||
|
signInManager.ConfigureExternalAuthenticationProperties(provider, |
||||
|
Url.Action(nameof(Callback), new { ReturnUrl = returnUrl })); |
||||
|
|
||||
|
return Challenge(properties, provider); |
||||
|
} |
||||
|
|
||||
|
[HttpGet] |
||||
|
[Route("account/callback/")] |
||||
|
public async Task<IActionResult> Callback(string returnUrl = null, string remoteError = null) |
||||
|
{ |
||||
|
var externalLogin = await signInManager.GetExternalLoginInfoAsync(); |
||||
|
|
||||
|
if (externalLogin == null) |
||||
|
{ |
||||
|
return RedirectToAction(nameof(Login)); |
||||
|
} |
||||
|
|
||||
|
var isLoggedIn = await LoginAsync(externalLogin); |
||||
|
|
||||
|
if (!isLoggedIn) |
||||
|
{ |
||||
|
var user = CreateUser(externalLogin); |
||||
|
|
||||
|
isLoggedIn = |
||||
|
await AddUserAsync(user) && |
||||
|
await AddLoginAsync(user, externalLogin) && |
||||
|
await LoginAsync(externalLogin); |
||||
|
} |
||||
|
|
||||
|
if (!isLoggedIn) |
||||
|
{ |
||||
|
return RedirectToAction(nameof(Login)); |
||||
|
} |
||||
|
else if (!string.IsNullOrWhiteSpace(returnUrl)) |
||||
|
{ |
||||
|
return Redirect(returnUrl); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
return Redirect("~/"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private async Task<bool> AddLoginAsync(IdentityUser user, UserLoginInfo externalLogin) |
||||
|
{ |
||||
|
var result = await userManager.AddLoginAsync(user, externalLogin); |
||||
|
|
||||
|
return result.Succeeded; |
||||
|
} |
||||
|
|
||||
|
private async Task<bool> AddUserAsync(IdentityUser user) |
||||
|
{ |
||||
|
var result = await userManager.CreateAsync(user); |
||||
|
|
||||
|
return result.Succeeded; |
||||
|
} |
||||
|
|
||||
|
private async Task<bool> LoginAsync(UserLoginInfo externalLogin) |
||||
|
{ |
||||
|
var result = await signInManager.ExternalLoginSignInAsync(externalLogin.LoginProvider, externalLogin.ProviderKey, true); |
||||
|
|
||||
|
return result.Succeeded; |
||||
|
} |
||||
|
|
||||
|
private static IdentityUser CreateUser(ExternalLoginInfo externalLogin) |
||||
|
{ |
||||
|
var mail = externalLogin.Principal.FindFirst(ClaimTypes.Email).Value; |
||||
|
|
||||
|
return new IdentityUser { Email = mail, UserName = mail }; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,23 @@ |
|||||
|
// ==========================================================================
|
||||
|
// ExternalProvider.cs
|
||||
|
// PinkParrot Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) PinkParrot Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
namespace PinkParrot.Modules.UI.Account |
||||
|
{ |
||||
|
public class ExternalProvider |
||||
|
{ |
||||
|
public string DisplayName { get; } |
||||
|
|
||||
|
public string AuthenticationScheme { get; } |
||||
|
|
||||
|
public ExternalProvider(string authenticationSchema, string displayName) |
||||
|
{ |
||||
|
AuthenticationScheme = authenticationSchema; |
||||
|
|
||||
|
DisplayName = displayName; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
// ==========================================================================
|
||||
|
// LoginVM.cs
|
||||
|
// PinkParrot Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) PinkParrot Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace PinkParrot.Modules.UI.Account |
||||
|
{ |
||||
|
public class LoginVM |
||||
|
{ |
||||
|
public string ReturnUrl { get; set; } |
||||
|
|
||||
|
public IEnumerable<ExternalProvider> ExternalProviders { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html> |
||||
|
<body> |
||||
|
<script src='~/scripts/oidc-client.min.js'></script> |
||||
|
<script> |
||||
|
Oidc.Log.logger = console; |
||||
|
Oidc.Log.logLevel = Oidc.Log.INFO; |
||||
|
|
||||
|
new Oidc.UserManager().signinPopupCallback(); |
||||
|
</script> |
||||
|
</body> |
||||
|
</html> |
||||
@ -0,0 +1,12 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html> |
||||
|
<body> |
||||
|
<script src='~/scripts/oidc-client.min.js'></script> |
||||
|
<script> |
||||
|
Oidc.Log.logger = console; |
||||
|
Oidc.Log.logLevel = Oidc.Log.INFO; |
||||
|
|
||||
|
new Oidc.UserManager().signinSilentCallback(); |
||||
|
</script> |
||||
|
</body> |
||||
|
</html> |
||||
@ -0,0 +1,15 @@ |
|||||
|
@using System.Collections.Generic |
||||
|
@using Microsoft.AspNetCore.Http |
||||
|
@using Microsoft.AspNetCore.Http.Authentication |
||||
|
@model PinkParrot.Modules.UI.Account.LoginVM |
||||
|
|
||||
|
<form asp-controller="Account" asp-action="External" asp-route-returnurl="@Model.ReturnUrl" method="post" class="form-horizontal"> |
||||
|
<div> |
||||
|
<p> |
||||
|
@foreach (var provider in Model.ExternalProviders) |
||||
|
{ |
||||
|
<button type="submit" class="btn btn-default" name="provider" value="@provider.AuthenticationScheme" title="Log in using your @provider.DisplayName account">@provider.AuthenticationScheme</button> |
||||
|
} |
||||
|
</p> |
||||
|
</div> |
||||
|
</form> |
||||
@ -0,0 +1,3 @@ |
|||||
|
@using Microsoft.AspNetCore.Identity |
||||
|
|
||||
|
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers |
||||
@ -0,0 +1,3 @@ |
|||||
|
@{ |
||||
|
Layout = null; |
||||
|
} |
||||
@ -1,3 +1 @@ |
|||||
<main> |
<router-outlet></router-outlet> |
||||
<h1>Hello from Angular 2 App with Webpack!</h1> |
|
||||
</main> |
|
||||
@ -1,16 +1,48 @@ |
|||||
import * as Ng2 from '@angular/core'; |
import * as Ng2 from '@angular/core'; |
||||
|
import * as Ng2Browser from '@angular/platform-browser'; |
||||
import { BrowserModule } from '@angular/platform-browser'; |
|
||||
|
|
||||
import { AppComponent } from './app.component'; |
import { AppComponent } from './app.component'; |
||||
|
|
||||
|
import { |
||||
|
ApiUrlConfig, |
||||
|
CurrencyConfig, |
||||
|
DragService, |
||||
|
DragServiceFactory, |
||||
|
DecimalSeparatorConfig, |
||||
|
} from './framework'; |
||||
|
|
||||
|
import { |
||||
|
AuthGuard, |
||||
|
AuthService, |
||||
|
} from './shared'; |
||||
|
|
||||
|
import { |
||||
|
MyAppModule, |
||||
|
MyLoginModule |
||||
|
} from './components'; |
||||
|
|
||||
|
import { routing } from './app.routes'; |
||||
|
|
||||
|
const baseUrl = window.location.protocol + '//' + window.location.host + '/'; |
||||
|
|
||||
@Ng2.NgModule({ |
@Ng2.NgModule({ |
||||
imports: [ |
imports: [ |
||||
BrowserModule |
Ng2Browser.BrowserModule, |
||||
|
MyAppModule, |
||||
|
MyLoginModule, |
||||
|
routing |
||||
], |
], |
||||
declarations: [ |
declarations: [ |
||||
AppComponent |
AppComponent |
||||
], |
], |
||||
|
providers: [ |
||||
|
AuthGuard, |
||||
|
AuthService, |
||||
|
{ provide: ApiUrlConfig, useValue: new ApiUrlConfig(baseUrl) }, |
||||
|
{ provide: CurrencyConfig, useValue: new CurrencyConfig('EUR', '€', true) }, |
||||
|
{ provide: DecimalSeparatorConfig, useValue: new DecimalSeparatorConfig('.') }, |
||||
|
{ provide: DragService, useFactory: DragServiceFactory } |
||||
|
], |
||||
bootstrap: [AppComponent] |
bootstrap: [AppComponent] |
||||
}) |
}) |
||||
export class AppModule { } |
export class AppModule { } |
||||
@ -0,0 +1,30 @@ |
|||||
|
import * as Ng2 from '@angular/core'; |
||||
|
import * as Ng2Router from '@angular/router'; |
||||
|
|
||||
|
import { |
||||
|
AppsComponent, |
||||
|
LoginComponent |
||||
|
} from './components'; |
||||
|
|
||||
|
import { |
||||
|
AuthGuard |
||||
|
} from './shared'; |
||||
|
|
||||
|
export const routes: Ng2Router.Routes = [ |
||||
|
{ |
||||
|
path: '', |
||||
|
redirectTo: 'apps', |
||||
|
pathMatch: 'full' |
||||
|
}, |
||||
|
{ |
||||
|
path: 'apps', |
||||
|
component: AppsComponent, |
||||
|
canActivate: [AuthGuard] |
||||
|
}, |
||||
|
{ |
||||
|
path: 'login', |
||||
|
component: LoginComponent |
||||
|
} |
||||
|
]; |
||||
|
|
||||
|
export const routing: Ng2.ModuleWithProviders = Ng2Router.RouterModule.forRoot(routes, { useHash: true }); |
||||
@ -0,0 +1,3 @@ |
|||||
|
<main> |
||||
|
<h1>Hello from Angular 2 App with Webpack!</h1> |
||||
|
</main> |
||||
@ -0,0 +1,16 @@ |
|||||
|
/* |
||||
|
*PinkParrot CMS |
||||
|
* |
||||
|
* @license |
||||
|
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
|
*/ |
||||
|
|
||||
|
import * as Ng2 from '@angular/core'; |
||||
|
|
||||
|
@Ng2.Component({ |
||||
|
selector: 'apps', |
||||
|
template |
||||
|
}) |
||||
|
export class AppsComponent { |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,24 @@ |
|||||
|
/* |
||||
|
*PinkParrot CMS |
||||
|
* |
||||
|
* @license |
||||
|
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
|
*/ |
||||
|
|
||||
|
import * as Ng2 from '@angular/core'; |
||||
|
|
||||
|
import { FrameworkModule } from './../../framework'; |
||||
|
|
||||
|
import { |
||||
|
AppsComponent |
||||
|
} from './declarations'; |
||||
|
|
||||
|
@Ng2.NgModule({ |
||||
|
imports: [ |
||||
|
FrameworkModule |
||||
|
], |
||||
|
declarations: [ |
||||
|
AppsComponent |
||||
|
] |
||||
|
}) |
||||
|
export class MyAppModule { } |
||||
@ -0,0 +1,8 @@ |
|||||
|
/* |
||||
|
*PinkParrot CMS |
||||
|
* |
||||
|
* @license |
||||
|
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
|
*/ |
||||
|
|
||||
|
export * from './apps.component'; |
||||
@ -0,0 +1,9 @@ |
|||||
|
/* |
||||
|
*PinkParrot CMS |
||||
|
* |
||||
|
* @license |
||||
|
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
|
*/ |
||||
|
|
||||
|
export * from './apps.component'; |
||||
|
export * from './apps.module'; |
||||
@ -0,0 +1,9 @@ |
|||||
|
/* |
||||
|
*PinkParrot CMS |
||||
|
* |
||||
|
* @license |
||||
|
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
|
*/ |
||||
|
|
||||
|
export * from './apps'; |
||||
|
export * from './login'; |
||||
@ -0,0 +1,8 @@ |
|||||
|
/* |
||||
|
*PinkParrot CMS |
||||
|
* |
||||
|
* @license |
||||
|
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
|
*/ |
||||
|
|
||||
|
export * from './login.component'; |
||||
@ -0,0 +1,9 @@ |
|||||
|
/* |
||||
|
*PinkParrot CMS |
||||
|
* |
||||
|
* @license |
||||
|
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
|
*/ |
||||
|
|
||||
|
export * from './login.component'; |
||||
|
export * from './login.module'; |
||||
@ -0,0 +1,3 @@ |
|||||
|
<div> |
||||
|
Logging in |
||||
|
</div> |
||||
@ -0,0 +1,36 @@ |
|||||
|
/* |
||||
|
*PinkParrot CMS |
||||
|
* |
||||
|
* @license |
||||
|
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
|
*/ |
||||
|
|
||||
|
import * as Ng2 from '@angular/core'; |
||||
|
import * as Ng2Common from '@angular/common'; |
||||
|
|
||||
|
import { AuthService } from './../../shared'; |
||||
|
|
||||
|
@Ng2.Component({ |
||||
|
selector: 'login', |
||||
|
template |
||||
|
}) |
||||
|
export class LoginComponent implements Ng2.OnInit { |
||||
|
public showFailedError = false; |
||||
|
|
||||
|
constructor( |
||||
|
private readonly authService: AuthService, |
||||
|
private readonly location: Ng2Common.Location |
||||
|
) { |
||||
|
} |
||||
|
|
||||
|
public ngOnInit() { |
||||
|
this.authService.login().subscribe( |
||||
|
() => { |
||||
|
this.location.back(); |
||||
|
}, |
||||
|
() => { |
||||
|
this.showFailedError = true; |
||||
|
} |
||||
|
); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,24 @@ |
|||||
|
/* |
||||
|
*PinkParrot CMS |
||||
|
* |
||||
|
* @license |
||||
|
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
|
*/ |
||||
|
|
||||
|
import * as Ng2 from '@angular/core'; |
||||
|
|
||||
|
import { FrameworkModule } from './../../framework'; |
||||
|
|
||||
|
import { |
||||
|
LoginComponent |
||||
|
} from './declarations'; |
||||
|
|
||||
|
@Ng2.NgModule({ |
||||
|
imports: [ |
||||
|
FrameworkModule |
||||
|
], |
||||
|
declarations: [ |
||||
|
LoginComponent |
||||
|
] |
||||
|
}) |
||||
|
export class MyLoginModule { } |
||||
@ -1,5 +1,5 @@ |
|||||
/* |
/* |
||||
* Athene Requirements Center |
*PinkParrot CMS |
||||
* |
* |
||||
* @license |
* @license |
||||
* Copyright (c) Sebastian Stehle. All rights reserved |
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
@ -1,5 +1,5 @@ |
|||||
/* |
/* |
||||
* Athene Requirements Center |
*PinkParrot CMS |
||||
* |
* |
||||
* @license |
* @license |
||||
* Copyright (c) Sebastian Stehle. All rights reserved |
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
@ -1,5 +1,5 @@ |
|||||
/* |
/* |
||||
* Athene Requirements Center |
*PinkParrot CMS |
||||
* |
* |
||||
* @license |
* @license |
||||
* Copyright (c) Sebastian Stehle. All rights reserved |
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
@ -1,12 +1,11 @@ |
|||||
/* |
/* |
||||
* Athene Requirements Center |
*PinkParrot CMS |
||||
* |
* |
||||
* @license |
* @license |
||||
* Copyright (c) Sebastian Stehle. All rights reserved |
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
*/ |
*/ |
||||
|
|
||||
import { Color } from './../'; |
import { Color } from './../'; |
||||
|
|
||||
import { ColorPickerComponent } from './color-picker.component'; |
import { ColorPickerComponent } from './color-picker.component'; |
||||
|
|
||||
describe('ColorPickerComponent', () => { |
describe('ColorPickerComponent', () => { |
||||
@ -1,5 +1,5 @@ |
|||||
/* |
/* |
||||
* Athene Requirements Center |
*PinkParrot CMS |
||||
* |
* |
||||
* @license |
* @license |
||||
* Copyright (c) Sebastian Stehle. All rights reserved |
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
@ -1,5 +1,5 @@ |
|||||
/* |
/* |
||||
* Athene Requirements Center |
*PinkParrot CMS |
||||
* |
* |
||||
* @license |
* @license |
||||
* Copyright (c) Sebastian Stehle. All rights reserved |
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
@ -1,5 +1,5 @@ |
|||||
/* |
/* |
||||
* Athene Requirements Center |
*PinkParrot CMS |
||||
* |
* |
||||
* @license |
* @license |
||||
* Copyright (c) Sebastian Stehle. All rights reserved |
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
@ -1,5 +1,5 @@ |
|||||
/* |
/* |
||||
* Athene Requirements Center |
*PinkParrot CMS |
||||
* |
* |
||||
* @license |
* @license |
||||
* Copyright (c) Sebastian Stehle. All rights reserved |
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
@ -1,5 +1,5 @@ |
|||||
/* |
/* |
||||
* Athene Requirements Center |
*PinkParrot CMS |
||||
* |
* |
||||
* @license |
* @license |
||||
* Copyright (c) Sebastian Stehle. All rights reserved |
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
@ -1,5 +1,5 @@ |
|||||
/* |
/* |
||||
* Athene Requirements Center |
*PinkParrot CMS |
||||
* |
* |
||||
* @license |
* @license |
||||
* Copyright (c) Sebastian Stehle. All rights reserved |
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
@ -1,5 +1,5 @@ |
|||||
/* |
/* |
||||
* Athene Requirements Center |
*PinkParrot CMS |
||||
* |
* |
||||
* @license |
* @license |
||||
* Copyright (c) Sebastian Stehle. All rights reserved |
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
@ -1,5 +1,5 @@ |
|||||
/* |
/* |
||||
* Athene Requirements Center |
*PinkParrot CMS |
||||
* |
* |
||||
* @license |
* @license |
||||
* Copyright (c) Sebastian Stehle. All rights reserved |
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
@ -1,5 +1,5 @@ |
|||||
/* |
/* |
||||
* Athene Requirements Center |
*PinkParrot CMS |
||||
* |
* |
||||
* @license |
* @license |
||||
* Copyright (c) Sebastian Stehle. All rights reserved |
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
@ -1,5 +1,5 @@ |
|||||
/* |
/* |
||||
* Athene Requirements Center |
*PinkParrot CMS |
||||
* |
* |
||||
* @license |
* @license |
||||
* Copyright (c) Sebastian Stehle. All rights reserved |
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
@ -1,5 +1,5 @@ |
|||||
/* |
/* |
||||
* Athene Requirements Center |
*PinkParrot CMS |
||||
* |
* |
||||
* @license |
* @license |
||||
* Copyright (c) Sebastian Stehle. All rights reserved |
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
@ -1,5 +1,5 @@ |
|||||
/* |
/* |
||||
* Athene Requirements Center |
*PinkParrot CMS |
||||
* |
* |
||||
* @license |
* @license |
||||
* Copyright (c) Sebastian Stehle. All rights reserved |
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
@ -1,26 +1,49 @@ |
|||||
/* |
/* |
||||
* Athene Requirements Center |
*PinkParrot CMS |
||||
* |
* |
||||
* @license |
* @license |
||||
* Copyright (c) Sebastian Stehle. All rights reserved |
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
*/ |
*/ |
||||
|
|
||||
|
import * as Ng2 from '@angular/core'; |
||||
|
|
||||
|
@Ng2.Injectable() |
||||
export class ApiUrlConfig { |
export class ApiUrlConfig { |
||||
constructor(public readonly value: string) { } |
public readonly value: string; |
||||
|
|
||||
|
constructor(value: string) { |
||||
|
if (value.indexOf('/', value.length - 1) < 0) { |
||||
|
value = value + '/'; |
||||
|
} |
||||
|
|
||||
|
this.value = value; |
||||
|
} |
||||
|
|
||||
|
public buildUrl(path: string) { |
||||
|
if (path.indexOf('/') === 0) { |
||||
|
path = path.substr(1); |
||||
|
} |
||||
|
|
||||
|
return this.value + path; |
||||
|
} |
||||
} |
} |
||||
|
|
||||
|
@Ng2.Injectable() |
||||
export class DecimalSeparatorConfig { |
export class DecimalSeparatorConfig { |
||||
constructor(public readonly value: string) { } |
constructor(public readonly value: string) { } |
||||
} |
} |
||||
|
|
||||
|
@Ng2.Injectable() |
||||
export class ProductionModeConfig { |
export class ProductionModeConfig { |
||||
constructor(public readonly isProductionMode: boolean) { } |
constructor(public readonly isProductionMode: boolean) { } |
||||
} |
} |
||||
|
|
||||
|
@Ng2.Injectable() |
||||
export class UserReportConfig { |
export class UserReportConfig { |
||||
constructor(public readonly siteId: string) { } |
constructor(public readonly siteId: string) { } |
||||
} |
} |
||||
|
|
||||
|
@Ng2.Injectable() |
||||
export class CurrencyConfig { |
export class CurrencyConfig { |
||||
constructor( |
constructor( |
||||
public readonly code: string, |
public readonly code: string, |
||||
@ -0,0 +1,13 @@ |
|||||
|
export * from './angular/cloak.directive'; |
||||
|
export * from './angular/color-picker.component'; |
||||
|
export * from './angular/date-time.pipes'; |
||||
|
export * from './angular/drag-model.directive'; |
||||
|
export * from './angular/focus-on-change.directive'; |
||||
|
export * from './angular/image-drop.directive'; |
||||
|
export * from './angular/money.pipe'; |
||||
|
export * from './angular/shortcut.component'; |
||||
|
export * from './angular/slider.component'; |
||||
|
export * from './angular/spinner.component'; |
||||
|
export * from './angular/user-report.component'; |
||||
|
export * from './services/drag.service'; |
||||
|
export * from './services/title.service'; |
||||
@ -0,0 +1,70 @@ |
|||||
|
import * as Ng2 from '@angular/core'; |
||||
|
import * as Ng2Http from '@angular/http'; |
||||
|
import * as Ng2Forms from '@angular/forms'; |
||||
|
import * as Ng2Common from '@angular/common'; |
||||
|
import * as Ng2Router from '@angular/router'; |
||||
|
|
||||
|
import { |
||||
|
CloakDirective, |
||||
|
ColorPickerComponent, |
||||
|
DayOfWeekPipe, |
||||
|
DayPipe, |
||||
|
DragModelDirective, |
||||
|
DurationPipe, |
||||
|
FocusOnChangeDirective, |
||||
|
ImageDropDirective, |
||||
|
MoneyPipe, |
||||
|
MonthPipe, |
||||
|
ShortcutComponent, |
||||
|
ShortDatePipe, |
||||
|
ShortTimePipe, |
||||
|
SliderComponent, |
||||
|
SpinnerComponent, |
||||
|
UserReportComponent |
||||
|
} from './declarations'; |
||||
|
|
||||
|
@Ng2.NgModule({ |
||||
|
imports: [ |
||||
|
Ng2Forms.FormsModule, |
||||
|
Ng2Common.CommonModule |
||||
|
], |
||||
|
declarations: [ |
||||
|
CloakDirective, |
||||
|
ColorPickerComponent, |
||||
|
DayOfWeekPipe, |
||||
|
DayPipe, |
||||
|
DragModelDirective, |
||||
|
DurationPipe, |
||||
|
FocusOnChangeDirective, |
||||
|
ImageDropDirective, |
||||
|
MoneyPipe, |
||||
|
MonthPipe, |
||||
|
ShortcutComponent, |
||||
|
ShortDatePipe, |
||||
|
ShortTimePipe, |
||||
|
SliderComponent, |
||||
|
SpinnerComponent, |
||||
|
UserReportComponent |
||||
|
], |
||||
|
exports: [ |
||||
|
CloakDirective, |
||||
|
ColorPickerComponent, |
||||
|
DayOfWeekPipe, |
||||
|
DayPipe, |
||||
|
DurationPipe, |
||||
|
FocusOnChangeDirective, |
||||
|
MoneyPipe, |
||||
|
MonthPipe, |
||||
|
ShortcutComponent, |
||||
|
ShortDatePipe, |
||||
|
ShortTimePipe, |
||||
|
SliderComponent, |
||||
|
SpinnerComponent, |
||||
|
UserReportComponent, |
||||
|
Ng2Http.HttpModule, |
||||
|
Ng2Forms.FormsModule, |
||||
|
Ng2Common.CommonModule, |
||||
|
Ng2Router.RouterModule |
||||
|
] |
||||
|
}) |
||||
|
export class FrameworkModule { } |
||||
@ -1,5 +1,5 @@ |
|||||
/* |
/* |
||||
* Athene Requirements Center |
*PinkParrot CMS |
||||
* |
* |
||||
* @license |
* @license |
||||
* Copyright (c) Sebastian Stehle. All rights reserved |
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
@ -1,5 +1,5 @@ |
|||||
/* |
/* |
||||
* Athene Requirements Center |
*PinkParrot CMS |
||||
* |
* |
||||
* @license |
* @license |
||||
* Copyright (c) Sebastian Stehle. All rights reserved |
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
@ -1,16 +1,19 @@ |
|||||
/* |
/* |
||||
* Athene Requirements Center |
*PinkParrot CMS |
||||
* |
* |
||||
* @license |
* @license |
||||
* Copyright (c) Sebastian Stehle. All rights reserved |
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
*/ |
*/ |
||||
|
|
||||
|
import * as Ng2 from '@angular/core'; |
||||
|
|
||||
import { BehaviorSubject, Observable } from 'rxjs'; |
import { BehaviorSubject, Observable } from 'rxjs'; |
||||
|
|
||||
export const ClipboardServiceFactory = () => { |
export const ClipboardServiceFactory = () => { |
||||
return new ClipboardService(); |
return new ClipboardService(); |
||||
}; |
}; |
||||
|
|
||||
|
@Ng2.Injectable() |
||||
export class ClipboardService { |
export class ClipboardService { |
||||
private textInstance = new BehaviorSubject<string>(''); |
private textInstance = new BehaviorSubject<string>(''); |
||||
|
|
||||
@ -1,5 +1,5 @@ |
|||||
/* |
/* |
||||
* Athene Requirements Center |
*PinkParrot CMS |
||||
* |
* |
||||
* @license |
* @license |
||||
* Copyright (c) Sebastian Stehle. All rights reserved |
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
@ -1,5 +1,5 @@ |
|||||
/* |
/* |
||||
* Athene Requirements Center |
*PinkParrot CMS |
||||
* |
* |
||||
* @license |
* @license |
||||
* Copyright (c) Sebastian Stehle. All rights reserved |
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
@ -1,14 +1,17 @@ |
|||||
/* |
/* |
||||
* Athene Requirements Center |
*PinkParrot CMS |
||||
* |
* |
||||
* @license |
* @license |
||||
* Copyright (c) Sebastian Stehle. All rights reserved |
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
*/ |
*/ |
||||
|
|
||||
|
import * as Ng2 from '@angular/core'; |
||||
|
|
||||
export const LocalStoreServiceFactory = () => { |
export const LocalStoreServiceFactory = () => { |
||||
return new LocalStoreService(); |
return new LocalStoreService(); |
||||
}; |
}; |
||||
|
|
||||
|
@Ng2.Injectable() |
||||
export class LocalStoreService { |
export class LocalStoreService { |
||||
private store: any = localStorage; |
private store: any = localStorage; |
||||
|
|
||||
@ -1,5 +1,5 @@ |
|||||
/* |
/* |
||||
* Athene Requirements Center |
*PinkParrot CMS |
||||
* |
* |
||||
* @license |
* @license |
||||
* Copyright (c) Sebastian Stehle. All rights reserved |
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
@ -1,14 +1,17 @@ |
|||||
/* |
/* |
||||
* Athene Requirements Center |
*PinkParrot CMS |
||||
* |
* |
||||
* @license |
* @license |
||||
* Copyright (c) Sebastian Stehle. All rights reserved |
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
*/ |
*/ |
||||
|
|
||||
|
import * as Ng2 from '@angular/core'; |
||||
|
|
||||
export const ShortcutServiceFactory = () => { |
export const ShortcutServiceFactory = () => { |
||||
return new ShortcutService(); |
return new ShortcutService(); |
||||
}; |
}; |
||||
|
|
||||
|
@Ng2.Injectable() |
||||
export class ShortcutService { |
export class ShortcutService { |
||||
public on(keys: string, callback: (e: KeyboardEvent, combo: string) => void) { |
public on(keys: string, callback: (e: KeyboardEvent, combo: string) => void) { |
||||
return Mousetrap.bind(keys, (event, combo) => { |
return Mousetrap.bind(keys, (event, combo) => { |
||||
@ -1,5 +1,5 @@ |
|||||
/* |
/* |
||||
* Athene Requirements Center |
*PinkParrot CMS |
||||
* |
* |
||||
* @license |
* @license |
||||
* Copyright (c) Sebastian Stehle. All rights reserved |
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
@ -1,5 +1,5 @@ |
|||||
/* |
/* |
||||
* Athene Requirements Center |
*PinkParrot CMS |
||||
* |
* |
||||
* @license |
* @license |
||||
* Copyright (c) Sebastian Stehle. All rights reserved |
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
@ -1,5 +1,5 @@ |
|||||
/* |
/* |
||||
* Athene Requirements Center |
*PinkParrot CMS |
||||
* |
* |
||||
* @license |
* @license |
||||
* Copyright (c) Sebastian Stehle. All rights reserved |
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
@ -1,5 +1,5 @@ |
|||||
/* |
/* |
||||
* Athene Requirements Center |
*PinkParrot CMS |
||||
* |
* |
||||
* @license |
* @license |
||||
* Copyright (c) Sebastian Stehle. All rights reserved |
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
@ -1,5 +1,5 @@ |
|||||
/* |
/* |
||||
* Athene Requirements Center |
*PinkParrot CMS |
||||
* |
* |
||||
* @license |
* @license |
||||
* Copyright (c) Sebastian Stehle. All rights reserved |
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
@ -1,5 +1,5 @@ |
|||||
/* |
/* |
||||
* Athene Requirements Center |
*PinkParrot CMS |
||||
* |
* |
||||
* @license |
* @license |
||||
* Copyright (c) Sebastian Stehle. All rights reserved |
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
@ -1,5 +1,5 @@ |
|||||
/* |
/* |
||||
* Athene Requirements Center |
*PinkParrot CMS |
||||
* |
* |
||||
* @license |
* @license |
||||
* Copyright (c) Sebastian Stehle. All rights reserved |
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
@ -1,5 +1,5 @@ |
|||||
/* |
/* |
||||
* Athene Requirements Center |
*PinkParrot CMS |
||||
* |
* |
||||
* @license |
* @license |
||||
* Copyright (c) Sebastian Stehle. All rights reserved |
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
@ -1,5 +1,5 @@ |
|||||
/* |
/* |
||||
* Athene Requirements Center |
*PinkParrot CMS |
||||
* |
* |
||||
* @license |
* @license |
||||
* Copyright (c) Sebastian Stehle. All rights reserved |
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue