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
|
|||
// ==========================================================================
|
|||
// Copyright (c) PinkParrot Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
namespace PinkParrot.Store.MongoDb |
|||
{ |
|||
public class MongoDbOptions |
|||
public class MyMongoDbOptions |
|||
{ |
|||
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
|
|||
// ==========================================================================
|
|||
// Copyright (c) PinkParrot Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
namespace PinkParrot.Configurations |
|||
namespace PinkParrot.Configurations.EventStore |
|||
{ |
|||
public sealed class EventStoreOptions |
|||
public sealed class MyEventStoreOptions |
|||
{ |
|||
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
|
|||
// ==========================================================================
|
|||
// Copyright (c) PinkParrot Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
namespace PinkParrot.Configurations |
|||
namespace PinkParrot.Configurations.Identity |
|||
{ |
|||
public sealed class IdentityOptions |
|||
public sealed class MyIdentityOptions |
|||
{ |
|||
public string DefaultUsername { 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> |
|||
<h1>Hello from Angular 2 App with Webpack!</h1> |
|||
</main> |
|||
<router-outlet></router-outlet> |
|||
@ -1,16 +1,48 @@ |
|||
import * as Ng2 from '@angular/core'; |
|||
|
|||
import { BrowserModule } from '@angular/platform-browser'; |
|||
import * as Ng2Browser from '@angular/platform-browser'; |
|||
|
|||
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({ |
|||
imports: [ |
|||
BrowserModule |
|||
Ng2Browser.BrowserModule, |
|||
MyAppModule, |
|||
MyLoginModule, |
|||
routing |
|||
], |
|||
declarations: [ |
|||
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] |
|||
}) |
|||
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 |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
@ -1,5 +1,5 @@ |
|||
/* |
|||
* Athene Requirements Center |
|||
*PinkParrot CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
@ -1,5 +1,5 @@ |
|||
/* |
|||
* Athene Requirements Center |
|||
*PinkParrot CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
@ -1,12 +1,11 @@ |
|||
/* |
|||
* Athene Requirements Center |
|||
*PinkParrot CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
*/ |
|||
|
|||
import { Color } from './../'; |
|||
|
|||
import { ColorPickerComponent } from './color-picker.component'; |
|||
|
|||
describe('ColorPickerComponent', () => { |
|||
@ -1,5 +1,5 @@ |
|||
/* |
|||
* Athene Requirements Center |
|||
*PinkParrot CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
@ -1,5 +1,5 @@ |
|||
/* |
|||
* Athene Requirements Center |
|||
*PinkParrot CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
@ -1,5 +1,5 @@ |
|||
/* |
|||
* Athene Requirements Center |
|||
*PinkParrot CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
@ -1,5 +1,5 @@ |
|||
/* |
|||
* Athene Requirements Center |
|||
*PinkParrot CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
@ -1,5 +1,5 @@ |
|||
/* |
|||
* Athene Requirements Center |
|||
*PinkParrot CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
@ -1,5 +1,5 @@ |
|||
/* |
|||
* Athene Requirements Center |
|||
*PinkParrot CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
@ -1,5 +1,5 @@ |
|||
/* |
|||
* Athene Requirements Center |
|||
*PinkParrot CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
@ -1,5 +1,5 @@ |
|||
/* |
|||
* Athene Requirements Center |
|||
*PinkParrot CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
@ -1,5 +1,5 @@ |
|||
/* |
|||
* Athene Requirements Center |
|||
*PinkParrot CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
@ -1,5 +1,5 @@ |
|||
/* |
|||
* Athene Requirements Center |
|||
*PinkParrot CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
@ -1,5 +1,5 @@ |
|||
/* |
|||
* Athene Requirements Center |
|||
*PinkParrot CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
@ -1,5 +1,5 @@ |
|||
/* |
|||
* Athene Requirements Center |
|||
*PinkParrot CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
@ -1,26 +1,49 @@ |
|||
/* |
|||
* Athene Requirements Center |
|||
*PinkParrot CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
*/ |
|||
|
|||
import * as Ng2 from '@angular/core'; |
|||
|
|||
@Ng2.Injectable() |
|||
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 { |
|||
constructor(public readonly value: string) { } |
|||
} |
|||
|
|||
@Ng2.Injectable() |
|||
export class ProductionModeConfig { |
|||
constructor(public readonly isProductionMode: boolean) { } |
|||
} |
|||
|
|||
@Ng2.Injectable() |
|||
export class UserReportConfig { |
|||
constructor(public readonly siteId: string) { } |
|||
} |
|||
|
|||
@Ng2.Injectable() |
|||
export class CurrencyConfig { |
|||
constructor( |
|||
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 |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
@ -1,5 +1,5 @@ |
|||
/* |
|||
* Athene Requirements Center |
|||
*PinkParrot CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
@ -1,16 +1,19 @@ |
|||
/* |
|||
* Athene Requirements Center |
|||
*PinkParrot CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
*/ |
|||
|
|||
import * as Ng2 from '@angular/core'; |
|||
|
|||
import { BehaviorSubject, Observable } from 'rxjs'; |
|||
|
|||
export const ClipboardServiceFactory = () => { |
|||
return new ClipboardService(); |
|||
}; |
|||
|
|||
@Ng2.Injectable() |
|||
export class ClipboardService { |
|||
private textInstance = new BehaviorSubject<string>(''); |
|||
|
|||
@ -1,5 +1,5 @@ |
|||
/* |
|||
* Athene Requirements Center |
|||
*PinkParrot CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
@ -1,5 +1,5 @@ |
|||
/* |
|||
* Athene Requirements Center |
|||
*PinkParrot CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
@ -1,14 +1,17 @@ |
|||
/* |
|||
* Athene Requirements Center |
|||
*PinkParrot CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
*/ |
|||
|
|||
import * as Ng2 from '@angular/core'; |
|||
|
|||
export const LocalStoreServiceFactory = () => { |
|||
return new LocalStoreService(); |
|||
}; |
|||
|
|||
@Ng2.Injectable() |
|||
export class LocalStoreService { |
|||
private store: any = localStorage; |
|||
|
|||
@ -1,5 +1,5 @@ |
|||
/* |
|||
* Athene Requirements Center |
|||
*PinkParrot CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
@ -1,14 +1,17 @@ |
|||
/* |
|||
* Athene Requirements Center |
|||
*PinkParrot CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
*/ |
|||
|
|||
import * as Ng2 from '@angular/core'; |
|||
|
|||
export const ShortcutServiceFactory = () => { |
|||
return new ShortcutService(); |
|||
}; |
|||
|
|||
@Ng2.Injectable() |
|||
export class ShortcutService { |
|||
public on(keys: string, callback: (e: KeyboardEvent, combo: string) => void) { |
|||
return Mousetrap.bind(keys, (event, combo) => { |
|||
@ -1,5 +1,5 @@ |
|||
/* |
|||
* Athene Requirements Center |
|||
*PinkParrot CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
@ -1,5 +1,5 @@ |
|||
/* |
|||
* Athene Requirements Center |
|||
*PinkParrot CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
@ -1,5 +1,5 @@ |
|||
/* |
|||
* Athene Requirements Center |
|||
*PinkParrot CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
@ -1,5 +1,5 @@ |
|||
/* |
|||
* Athene Requirements Center |
|||
*PinkParrot CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
@ -1,5 +1,5 @@ |
|||
/* |
|||
* Athene Requirements Center |
|||
*PinkParrot CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
@ -1,5 +1,5 @@ |
|||
/* |
|||
* Athene Requirements Center |
|||
*PinkParrot CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
@ -1,5 +1,5 @@ |
|||
/* |
|||
* Athene Requirements Center |
|||
*PinkParrot CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
@ -1,5 +1,5 @@ |
|||
/* |
|||
* Athene Requirements Center |
|||
*PinkParrot CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
@ -1,5 +1,5 @@ |
|||
/* |
|||
* Athene Requirements Center |
|||
*PinkParrot CMS |
|||
* |
|||
* @license |
|||
* 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