-Paket -TutorialFiles
Removed Paket files (could not get reliable builds; we may revisit once .NET core has stablizied); removed extraneous tutorial files; currently blocked getting Auth0 Lock to load from within Aurelia app
This commit is contained in:
parent
b0b20df36d
commit
55cf47af18
9
.gitignore
vendored
9
.gitignore
vendored
@ -252,8 +252,9 @@ paket-files/
|
|||||||
.idea/
|
.idea/
|
||||||
*.sln.iml
|
*.sln.iml
|
||||||
|
|
||||||
# Elm temporary files
|
# Compiled files / application
|
||||||
src/elm-stuff
|
**/vendor-bundle.js
|
||||||
# Compiled application
|
**/app-bundle.js*
|
||||||
src/wwwroot/app.js
|
src/api/wwwroot/index.html
|
||||||
|
src/api/appsettings.json
|
||||||
build/
|
build/
|
@ -1,108 +0,0 @@
|
|||||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<PropertyGroup>
|
|
||||||
<!-- Mark that this target file has been loaded. -->
|
|
||||||
<IsPaketRestoreTargetsFileLoaded>true</IsPaketRestoreTargetsFileLoaded>
|
|
||||||
<PaketToolsPath>$(MSBuildThisFileDirectory)</PaketToolsPath>
|
|
||||||
<MonoPath Condition="'$(MonoPath)' == '' And Exists('/Library/Frameworks/Mono.framework/Commands/mono')">/Library/Frameworks/Mono.framework/Commands/mono</MonoPath>
|
|
||||||
<MonoPath Condition="'$(MonoPath)' == ''">mono</MonoPath>
|
|
||||||
<!-- Paket command -->
|
|
||||||
<PaketExePath Condition=" '$(PaketExePath)' == '' AND Exists('$(PaketRootPath)paket.exe')">$(PaketRootPath)paket.exe</PaketExePath>
|
|
||||||
<PaketExePath Condition=" '$(PaketExePath)' == '' ">$(PaketToolsPath)paket.exe</PaketExePath>
|
|
||||||
<PaketCommand Condition=" '$(OS)' == 'Windows_NT'">"$(PaketExePath)"</PaketCommand>
|
|
||||||
<PaketCommand Condition=" '$(OS)' != 'Windows_NT' ">$(MonoPath) --runtime=v4.0.30319 "$(PaketExePath)"</PaketCommand>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<Target Name="PaketRestore" BeforeTargets="_GenerateProjectRestoreGraphPerFramework;_GenerateRestoreGraphWalkPerFramework;CollectPackageReferences" >
|
|
||||||
|
|
||||||
<Exec Command='$(PaketCommand) restore --project "$(MSBuildProjectFullPath)" ' />
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<PaketReferencesFilePath>$(MSBuildProjectDirectory)/obj/$(MSBuildProjectFile).references</PaketReferencesFilePath>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ReadLinesFromFile File="$(PaketReferencesFilePath)" >
|
|
||||||
<Output TaskParameter="Lines" ItemName="PaketReferencesFileLines"/>
|
|
||||||
</ReadLinesFromFile>
|
|
||||||
|
|
||||||
<ItemGroup Condition=" '@(PaketReferencesFileLines)' != '' " >
|
|
||||||
<PaketReferencesFileLinesInfo Include="@(PaketReferencesFileLines)" >
|
|
||||||
<PackageName>$([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[0])</PackageName>
|
|
||||||
<PackageVersion>$([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[1])</PackageVersion>
|
|
||||||
</PaketReferencesFileLinesInfo>
|
|
||||||
<PackageReference Include="%(PaketReferencesFileLinesInfo.PackageName)">
|
|
||||||
<Version>%(PaketReferencesFileLinesInfo.PackageVersion)</Version>
|
|
||||||
</PackageReference>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<RestoreConfigFile>$(MSBuildProjectDirectory)/obj/$(MSBuildProjectFile).NuGet.Config</RestoreConfigFile>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
</Target>
|
|
||||||
|
|
||||||
<Target Name="PaketDisableDirectPack" AfterTargets="_IntermediatePack" BeforeTargets="GenerateNuspec" >
|
|
||||||
<PropertyGroup>
|
|
||||||
<ContinuePackingAfterGeneratingNuspec>false</ContinuePackingAfterGeneratingNuspec>
|
|
||||||
</PropertyGroup>
|
|
||||||
</Target>
|
|
||||||
|
|
||||||
<Target Name="PaketOverrideNuspec" AfterTargets="GenerateNuspec" >
|
|
||||||
<PropertyGroup>
|
|
||||||
<PaketReferencesFilePath>$(MSBuildProjectDirectory)/obj/$(MSBuildProjectFile).references</PaketReferencesFilePath>
|
|
||||||
<ContinuePackingAfterGeneratingNuspec>true</ContinuePackingAfterGeneratingNuspec>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<_NuspecFiles Include="$(BaseIntermediateOutputPath)*.nuspec"/>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<Exec Command='$(PaketCommand) fix-nuspec file "@(_NuspecFiles)" references-file "$(PaketReferencesFilePath)" ' />
|
|
||||||
|
|
||||||
<ConvertToAbsolutePath Condition="@(_NuspecFiles) != ''" Paths="@(_NuspecFiles)">
|
|
||||||
<Output TaskParameter="AbsolutePaths" PropertyName="NuspecFileAbsolutePath" />
|
|
||||||
</ConvertToAbsolutePath>
|
|
||||||
|
|
||||||
<!-- Call Pack -->
|
|
||||||
<PackTask PackItem="$(PackProjectInputFile)"
|
|
||||||
PackageFiles="@(_PackageFiles)"
|
|
||||||
PackageFilesToExclude="@(_PackageFilesToExclude)"
|
|
||||||
PackageVersion="$(PackageVersion)"
|
|
||||||
PackageId="$(PackageId)"
|
|
||||||
Title="$(Title)"
|
|
||||||
Authors="$(Authors)"
|
|
||||||
Description="$(Description)"
|
|
||||||
Copyright="$(Copyright)"
|
|
||||||
RequireLicenseAcceptance="$(PackageRequireLicenseAcceptance)"
|
|
||||||
LicenseUrl="$(PackageLicenseUrl)"
|
|
||||||
ProjectUrl="$(PackageProjectUrl)"
|
|
||||||
IconUrl="$(PackageIconUrl)"
|
|
||||||
ReleaseNotes="$(PackageReleaseNotes)"
|
|
||||||
Tags="$(PackageTags)"
|
|
||||||
TargetPathsToAssemblies="@(_TargetPathsToAssemblies->'%(FinalOutputPath)')"
|
|
||||||
TargetPathsToSymbols="@(_TargetPathsToSymbols)"
|
|
||||||
TargetFrameworks="@(_TargetFrameworks)"
|
|
||||||
AssemblyName="$(AssemblyName)"
|
|
||||||
PackageOutputPath="$(PackageOutputAbsolutePath)"
|
|
||||||
IncludeSymbols="$(IncludeSymbols)"
|
|
||||||
IncludeSource="$(IncludeSource)"
|
|
||||||
PackageTypes="$(PackageType)"
|
|
||||||
IsTool="$(IsTool)"
|
|
||||||
RepositoryUrl="$(RepositoryUrl)"
|
|
||||||
RepositoryType="$(RepositoryType)"
|
|
||||||
SourceFiles="@(_SourceFiles->Distinct())"
|
|
||||||
NoPackageAnalysis="$(NoPackageAnalysis)"
|
|
||||||
MinClientVersion="$(MinClientVersion)"
|
|
||||||
Serviceable="$(Serviceable)"
|
|
||||||
AssemblyReferences="@(_References)"
|
|
||||||
ContinuePackingAfterGeneratingNuspec="$(ContinuePackingAfterGeneratingNuspec)"
|
|
||||||
NuspecOutputPath="$(BaseIntermediateOutputPath)"
|
|
||||||
IncludeBuildOutput="$(IncludeBuildOutput)"
|
|
||||||
BuildOutputFolder="$(BuildOutputTargetFolder)"
|
|
||||||
ContentTargetFolders="$(ContentTargetFolders)"
|
|
||||||
RestoreOutputPath="$(RestoreOutputAbsolutePath)"
|
|
||||||
NuspecFile="$(NuspecFileAbsolutePath)"
|
|
||||||
NuspecBasePath="$(NuspecBasePath)"
|
|
||||||
NuspecProperties="$(NuspecProperties)"/>
|
|
||||||
</Target>
|
|
||||||
|
|
||||||
</Project>
|
|
Binary file not shown.
@ -1,8 +1,4 @@
|
|||||||
@echo off
|
@echo off
|
||||||
cls
|
cls
|
||||||
.paket\paket.exe restore
|
|
||||||
if errorlevel 1 (
|
|
||||||
exit /b %errorlevel%
|
|
||||||
)
|
|
||||||
"packages\FAKE\tools\Fake.exe" build.fsx %1
|
"packages\FAKE\tools\Fake.exe" build.fsx %1
|
||||||
pause
|
pause
|
19
build.fsx
19
build.fsx
@ -38,12 +38,27 @@ Target "CopyApp" (fun _ ->
|
|||||||
)
|
)
|
||||||
|
|
||||||
Target "BuildApi" (fun _ ->
|
Target "BuildApi" (fun _ ->
|
||||||
!! "src/api/*.fsproj"
|
let result =
|
||||||
|
ExecProcessAndReturnMessages (fun info ->
|
||||||
|
info.UseShellExecute <- false
|
||||||
|
info.FileName <- "dotnet"
|
||||||
|
info.Arguments <- "build"
|
||||||
|
info.WorkingDirectory <- "src" @@ "api") (TimeSpan.FromMinutes 2.)
|
||||||
|
Log "AppBuild-Output: " result.Messages
|
||||||
|
match result.ExitCode with
|
||||||
|
| 0 -> ()
|
||||||
|
| _ -> failwith "API build failed"
|
||||||
|
(*!! "src/api/*.fsproj"
|
||||||
|> MSBuildRelease buildDir "Build"
|
|> MSBuildRelease buildDir "Build"
|
||||||
|> Log "ApiBuild-Output: "
|
|> Log "ApiBuild-Output: " *)
|
||||||
)
|
)
|
||||||
|
|
||||||
Target "Run" (fun _ ->
|
Target "Run" (fun _ ->
|
||||||
|
ExecProcess (fun info ->
|
||||||
|
info.FileName <- "dotnet"
|
||||||
|
info.Arguments <- """publish -o ..\..\build"""
|
||||||
|
info.WorkingDirectory <- "src" @@ "api") TimeSpan.MaxValue
|
||||||
|
|> ignore
|
||||||
ExecProcess (fun info ->
|
ExecProcess (fun info ->
|
||||||
info.FileName <- "dotnet"
|
info.FileName <- "dotnet"
|
||||||
info.Arguments <- "myPrayerJournal.dll"
|
info.Arguments <- "myPrayerJournal.dll"
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
source https://api.nuget.org/v3/index.json
|
|
||||||
nuget Auth0.AuthenticationApi
|
|
||||||
nuget FAKE
|
|
||||||
nuget FSharp.Core
|
|
||||||
nuget FSharp.NET.Sdk
|
|
||||||
nuget jose-jwt
|
|
||||||
nuget Microsoft.EntityFrameworkCore.Tools
|
|
||||||
nuget Newtonsoft.Json
|
|
||||||
nuget Npgsql.EntityFrameworkCore.PostgreSQL
|
|
||||||
nuget Suave
|
|
||||||
nuget Suave.Experimental
|
|
1065
paket.lock
1065
paket.lock
File diff suppressed because it is too large
Load Diff
@ -78,8 +78,7 @@ let schemeHostPort (req : HttpRequest) =
|
|||||||
/// Authorization functions
|
/// Authorization functions
|
||||||
module Auth =
|
module Auth =
|
||||||
|
|
||||||
open Views
|
(*
|
||||||
|
|
||||||
let exchangeCodeForToken code = context (fun ctx ->
|
let exchangeCodeForToken code = context (fun ctx ->
|
||||||
async {
|
async {
|
||||||
let client = AuthenticationApiClient (Uri (sprintf "https://%s" cfg.Auth0.Domain))
|
let client = AuthenticationApiClient (Uri (sprintf "https://%s" cfg.Auth0.Domain))
|
||||||
@ -120,7 +119,7 @@ module Auth =
|
|||||||
match ctx |> HttpContext.state with
|
match ctx |> HttpContext.state with
|
||||||
| Some state -> state.set "auth-key" null
|
| Some state -> state.set "auth-key" null
|
||||||
| _ -> succeed
|
| _ -> succeed
|
||||||
>=> FOUND (sprintf "%s/" (schemeHostPort ctx.request)))
|
>=> FOUND (sprintf "%s/" (schemeHostPort ctx.request))) *)
|
||||||
|
|
||||||
let cw (x : string) = Console.WriteLine x
|
let cw (x : string) = Console.WriteLine x
|
||||||
|
|
||||||
@ -152,7 +151,7 @@ module Auth =
|
|||||||
| _ -> Writers.setUserData "user" None)
|
| _ -> Writers.setUserData "user" None)
|
||||||
|
|
||||||
/// Create a user context for the currently assigned user
|
/// Create a user context for the currently assigned user
|
||||||
let userCtx ctx = { Id = ctx.userState.["user"] :?> string option }
|
//let userCtx ctx = { Id = ctx.userState.["user"] :?> string option }
|
||||||
|
|
||||||
/// Read an item from the user state, downcast to the expected type
|
/// Read an item from the user state, downcast to the expected type
|
||||||
let read ctx key : 'value =
|
let read ctx key : 'value =
|
||||||
@ -164,17 +163,17 @@ let dataCtx () =
|
|||||||
|
|
||||||
/// Return an HTML page
|
/// Return an HTML page
|
||||||
let html ctx content =
|
let html ctx content =
|
||||||
Views.page (Auth.userCtx ctx) content
|
""//Views.page (Auth.userCtx ctx) content
|
||||||
|
|
||||||
/// Home page
|
/// Home page
|
||||||
let viewHome = warbler (fun ctx -> OK (Views.home |> html ctx))
|
let viewHome = warbler (fun ctx -> OK ("" (*Views.home*) |> html ctx))
|
||||||
|
|
||||||
/// Journal page
|
/// Journal page
|
||||||
let viewJournal =
|
let viewJournal =
|
||||||
context (fun ctx ->
|
context (fun ctx ->
|
||||||
use dataCtx = dataCtx ()
|
use dataCtx = dataCtx ()
|
||||||
let reqs = Data.Requests.allForUser (defaultArg (read ctx "user") "") dataCtx
|
let reqs = Data.Requests.allForUser (defaultArg (read ctx "user") "") dataCtx
|
||||||
OK (Views.journal reqs |> html ctx))
|
OK ("" (*Views.journal reqs*) |> html ctx))
|
||||||
|
|
||||||
let idx =
|
let idx =
|
||||||
context (fun ctx ->
|
context (fun ctx ->
|
||||||
@ -187,8 +186,8 @@ let app =
|
|||||||
>=> choose [
|
>=> choose [
|
||||||
path Route.home >=> Files.browseFileHome "index.html"
|
path Route.home >=> Files.browseFileHome "index.html"
|
||||||
path Route.journal >=> viewJournal
|
path Route.journal >=> viewJournal
|
||||||
path Route.User.logOn >=> Auth.handleSignIn
|
//path Route.User.logOn >=> Auth.handleSignIn
|
||||||
path Route.User.logOff >=> Auth.handleSignOut
|
//path Route.User.logOff >=> Auth.handleSignOut
|
||||||
Writers.setHeader "Cache-Control" "no-cache" >=> Files.browseHome
|
Writers.setHeader "Cache-Control" "no-cache" >=> Files.browseHome
|
||||||
NOT_FOUND "Page not found."
|
NOT_FOUND "Page not found."
|
||||||
]
|
]
|
||||||
@ -214,14 +213,7 @@ let main argv =
|
|||||||
// Establish the data environment
|
// Establish the data environment
|
||||||
//liftDep getConn (Data.establishEnvironment >> Async.RunSynchronously)
|
//liftDep getConn (Data.establishEnvironment >> Async.RunSynchronously)
|
||||||
//|> run deps
|
//|> run deps
|
||||||
let writeKey key = File.WriteAllText ("key.txt", key)
|
|
||||||
Crypto.generateKey Crypto.KeySize
|
|
||||||
|> Convert.ToBase64String
|
|
||||||
|> writeKey
|
|
||||||
|
|
||||||
ensureDatabase ()
|
ensureDatabase ()
|
||||||
startWebServer suaveCfg app
|
startWebServer suaveCfg app
|
||||||
0
|
0
|
||||||
(*
|
|
||||||
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2Rqcy1jb25zdWx0aW5nLmF1dGgwLmNvbS8iLCJzdWIiOiJ3aW5kb3dzbGl2ZXw3OTMyNGZhMTM4MzZlZGNiIiwiYXVkIjoiT2YyczBSUUNRM210M2R3SWtPQlk1aDg1SjlzWGJGMm4iLCJleHAiOjE0OTI5MDc1OTAsImlhdCI6MTQ5Mjg3MTU5MH0.61JPm3Hz7XW-iaSq8Esv1cajQPbK0o9L5xz-RHIYq9g
|
|
||||||
*)
|
|
@ -1,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="FSharp.NET.Sdk;Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<VersionPrefix>0.8.1</VersionPrefix>
|
<VersionPrefix>0.8.1</VersionPrefix>
|
||||||
@ -17,7 +17,6 @@
|
|||||||
<Compile Include="Migrations/20170104023341_InitialDb.fs" />
|
<Compile Include="Migrations/20170104023341_InitialDb.fs" />
|
||||||
<Compile Include="Migrations/DataContextModelSnapshot.fs" />
|
<Compile Include="Migrations/DataContextModelSnapshot.fs" />
|
||||||
<Compile Include="Route.fs" />
|
<Compile Include="Route.fs" />
|
||||||
<Compile Include="Views.fs" />
|
|
||||||
<Compile Include="App.fs" />
|
<Compile Include="App.fs" />
|
||||||
<None Update="appsettings.json">
|
<None Update="appsettings.json">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
@ -27,9 +26,31 @@
|
|||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<Import Project="..\..\packages\FSharp.NET.Sdk\build\FSharp.NET.Core.Sdk.targets" />
|
<!-- Import Project="..\..\.paket\Paket.Restore.targets" / -->
|
||||||
<Import Project="..\..\.paket\Paket.Restore.targets" />
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Auth0.AuthenticationApi">
|
||||||
|
<Version>4.1.0</Version>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="FSharp.Core">
|
||||||
|
<Version>4.1.17</Version>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="FSharp.NET.Sdk">
|
||||||
|
<Version>1.0.5</Version>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="jose-jwt">
|
||||||
|
<Version>2.3.0</Version>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Newtonsoft.Json">
|
||||||
|
<Version>10.0.2</Version>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL">
|
||||||
|
<Version>1.1.0</Version>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Suave">
|
||||||
|
<Version>2.1.0</Version>
|
||||||
|
</PackageReference>
|
||||||
|
|
||||||
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="1.0.0" />
|
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="1.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
113
src/api/Views.fs
113
src/api/Views.fs
@ -1,113 +0,0 @@
|
|||||||
module MyPrayerJournal.Views
|
|
||||||
|
|
||||||
//open Suave.Html
|
|
||||||
open Suave.Xml
|
|
||||||
|
|
||||||
type UserContext = { Id: string option }
|
|
||||||
|
|
||||||
[<AutoOpen>]
|
|
||||||
module Tags =
|
|
||||||
/// Generate a meta tag
|
|
||||||
let meta attr = tag "meta" attr empty
|
|
||||||
|
|
||||||
/// Generate a link to a stylesheet
|
|
||||||
let stylesheet url = linkAttr [ "rel", "stylesheet"; "href", url ]
|
|
||||||
|
|
||||||
let aAttr attr x = tag "a" attr (flatten x)
|
|
||||||
let a = aAttr []
|
|
||||||
let buttonAttr attr x = tag "button" attr (flatten x)
|
|
||||||
let button = buttonAttr []
|
|
||||||
|
|
||||||
let footerAttr attr x = tag "footer" attr (flatten x)
|
|
||||||
let footer = footerAttr []
|
|
||||||
let ulAttr attr x = tag "ul" attr (flatten x)
|
|
||||||
let ul = ulAttr []
|
|
||||||
|
|
||||||
/// Used to prevent a self-closing tag where we need no text
|
|
||||||
let noText = text ""
|
|
||||||
let navLinkAttr attr url linkText = aAttr (("href", url) :: attr) [ text linkText ]
|
|
||||||
|
|
||||||
let navLink = navLinkAttr []
|
|
||||||
|
|
||||||
let jsLink func linkText = navLinkAttr [ "onclick", func ] "javascript:void(0)" linkText
|
|
||||||
|
|
||||||
/// Create a link to a JavaScript file
|
|
||||||
let js src = scriptAttr [ "src", src ] [ noText ]
|
|
||||||
|
|
||||||
[<AutoOpen>]
|
|
||||||
module PageComponents =
|
|
||||||
let prependDoctype document = sprintf "<!DOCTYPE html>\n%s" document
|
|
||||||
let render = xmlToString >> prependDoctype
|
|
||||||
|
|
||||||
let navigation userCtx =
|
|
||||||
[
|
|
||||||
match userCtx.Id with
|
|
||||||
| Some _ ->
|
|
||||||
yield navLink Route.journal "Journal"
|
|
||||||
yield navLink Route.User.logOff "Log Off"
|
|
||||||
| _ -> yield jsLink "mpj.signIn()" "Log On"
|
|
||||||
|
|
||||||
]
|
|
||||||
|> List.map (fun x -> tag "li" [] x)
|
|
||||||
let pageHeader userCtx =
|
|
||||||
divAttr [ "class", "navbar navbar-inverse navbar-fixed-top" ] [
|
|
||||||
divAttr [ "class", "container" ] [
|
|
||||||
divAttr [ "class", "navbar-header" ] [
|
|
||||||
buttonAttr [ "class", "navbar-toggle"; "data-toggle", "collapse"; "data-target", ".navbar-collapse" ] [
|
|
||||||
spanAttr [ "class", "sr-only" ] (text "Toggle navigation")
|
|
||||||
spanAttr [ "class", "icon-bar" ] noText
|
|
||||||
spanAttr [ "class", "icon-bar" ] noText
|
|
||||||
spanAttr [ "class", "icon-bar" ] noText
|
|
||||||
]
|
|
||||||
navLinkAttr [ "class", "navbar-brand" ] "/" "myPrayerJournal"
|
|
||||||
]
|
|
||||||
divAttr [ "class", "navbar-collapse collapse" ] [
|
|
||||||
ulAttr [ "class", "nav navbar-nav navbar-right" ] (navigation userCtx)
|
|
||||||
]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
let pageFooter =
|
|
||||||
footerAttr [ "class", "mpj-footer" ] [
|
|
||||||
pAttr [ "class", "text-right" ] [
|
|
||||||
text "myPrayerJournal v0.8.1"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
let row = divAttr [ "class", "row" ]
|
|
||||||
|
|
||||||
let fullRow xml =
|
|
||||||
row [ divAttr [ "class", "col-xs-12" ] xml ]
|
|
||||||
|
|
||||||
/// Display a page
|
|
||||||
let page userCtx content =
|
|
||||||
html [
|
|
||||||
head [
|
|
||||||
meta [ "charset", "UTF-8" ]
|
|
||||||
meta [ "name", "viewport"; "content", "width=device-width, initial-scale=1" ]
|
|
||||||
title "myPrayerJournal"
|
|
||||||
stylesheet "https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.6/css/bootstrap.min.css"
|
|
||||||
stylesheet "/content/styles.css"
|
|
||||||
stylesheet "https://fonts.googleapis.com/icon?family=Material+Icons"
|
|
||||||
]
|
|
||||||
body [
|
|
||||||
pageHeader userCtx
|
|
||||||
divAttr [ "class", "container body-content" ] [
|
|
||||||
content
|
|
||||||
pageFooter
|
|
||||||
]
|
|
||||||
js "https://cdn.auth0.com/js/lock/10.14/lock.min.js"
|
|
||||||
js "/js/mpj.js"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|> render
|
|
||||||
|
|
||||||
let home =
|
|
||||||
fullRow [
|
|
||||||
p [ text " "]
|
|
||||||
p [ text "myPrayerJournal is a place where individuals can record their prayer requests, record that they prayed for them, update them as God moves in the situation, and record a final answer received on that request. It will also allow individuals to review their answered prayers." ]
|
|
||||||
p [ text "This site is currently in very limited alpha, as it is being developed with a core group of test users. If this is something you are interested in using, check back around mid-February 2017 to check on the development progress." ]
|
|
||||||
]
|
|
||||||
|
|
||||||
let journal (reqs : Request list) =
|
|
||||||
fullRow [
|
|
||||||
p [ text "journal goes here" ]
|
|
||||||
]
|
|
@ -1,6 +0,0 @@
|
|||||||
Auth0.AuthenticationApi
|
|
||||||
jose-jwt
|
|
||||||
Newtonsoft.Json
|
|
||||||
Npgsql.EntityFrameworkCore.PostgreSQL
|
|
||||||
Suave
|
|
||||||
Suave.Experimental
|
|
@ -100,6 +100,7 @@
|
|||||||
"aurelia-dependency-injection",
|
"aurelia-dependency-injection",
|
||||||
"aurelia-event-aggregator",
|
"aurelia-event-aggregator",
|
||||||
"aurelia-framework",
|
"aurelia-framework",
|
||||||
|
"aurelia-fetch-client",
|
||||||
"aurelia-history",
|
"aurelia-history",
|
||||||
"aurelia-history-browser",
|
"aurelia-history-browser",
|
||||||
"aurelia-loader",
|
"aurelia-loader",
|
||||||
@ -151,6 +152,11 @@
|
|||||||
"resources": [
|
"resources": [
|
||||||
"nprogress.css"
|
"nprogress.css"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "auth0-lock",
|
||||||
|
"path": "../node_modules/auth0-lock",
|
||||||
|
"main": "lib/index"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"aurelia-animator-css": "^1.0.1",
|
"aurelia-animator-css": "^1.0.1",
|
||||||
"aurelia-bootstrapper": "^2.1.0",
|
"aurelia-bootstrapper": "^2.1.0",
|
||||||
|
"aurelia-fetch-client": "^1.1.2",
|
||||||
|
"auth0-lock": "^10.16.0",
|
||||||
"bluebird": "^3.4.1",
|
"bluebird": "^3.4.1",
|
||||||
"bootstrap": "^3.3.7",
|
"bootstrap": "^3.3.7",
|
||||||
"jquery": "^2.2.4",
|
"jquery": "^2.2.4",
|
||||||
|
1
src/app/scripts/vendor-bundle.js.map
Normal file
1
src/app/scripts/vendor-bundle.js.map
Normal file
File diff suppressed because one or more lines are too long
@ -15,6 +15,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="navbar-collapse collapse">
|
<div class="navbar-collapse collapse">
|
||||||
<ul class="nav navbar-nav navbar-right">
|
<ul class="nav navbar-nav navbar-right">
|
||||||
|
<li if.bind="!isAuthenticated()" click.delegate="logon()">Log On</li>
|
||||||
|
<li if.bind="isAuthenticated()" click.delegate="logoff()">Log Off</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,16 +1,66 @@
|
|||||||
import {Router, RouterConfiguration} from "aurelia-router"
|
import {Router, RouterConfiguration} from "aurelia-router"
|
||||||
import {EventAggregator} from "aurelia-event-aggregator"
|
import {EventAggregator} from "aurelia-event-aggregator"
|
||||||
import {inject} from "aurelia-framework"
|
import {inject} from "aurelia-framework"
|
||||||
|
import {HttpClient} from "aurelia-fetch-client"
|
||||||
import {PageTitle} from "./messages"
|
import {PageTitle} from "./messages"
|
||||||
import {WebAPI} from "./web-api"
|
import {Auth0Lock} from "auth0-lock"
|
||||||
|
|
||||||
@inject(WebAPI, EventAggregator)
|
@inject(EventAggregator, HttpClient)
|
||||||
export class App {
|
export class App {
|
||||||
router: Router;
|
router: Router;
|
||||||
pageTitle: string;
|
pageTitle: string;
|
||||||
|
|
||||||
|
lock = new Auth0Lock('Of2s0RQCQ3mt3dwIkOBY5h85J9sXbF2n', 'djs-consulting.auth0.com', {
|
||||||
|
oidcConformant: true,
|
||||||
|
autoclose: true,
|
||||||
|
auth: {
|
||||||
|
redirectUrl: "http://localhost:8080/user/log-on",
|
||||||
|
responseType: 'token id_token',
|
||||||
|
audience: `https://djs-consulting.auth0.com/userinfo`,
|
||||||
|
params: {
|
||||||
|
scope: 'openid'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
constructor(public api: WebAPI, private ea: EventAggregator) {
|
private setSession(authResult): void {
|
||||||
|
// Set the time that the access token will expire at
|
||||||
|
const expiresAt = JSON.stringify((authResult.expiresIn * 1000) + new Date().getTime())
|
||||||
|
localStorage.setItem('access_token', authResult.accessToken)
|
||||||
|
localStorage.setItem('id_token', authResult.idToken)
|
||||||
|
localStorage.setItem('expires_at', expiresAt)
|
||||||
|
}
|
||||||
|
|
||||||
|
public logoff(): void {
|
||||||
|
// Remove tokens and expiry time from localStorage
|
||||||
|
localStorage.removeItem('access_token')
|
||||||
|
localStorage.removeItem('id_token')
|
||||||
|
localStorage.removeItem('expires_at')
|
||||||
|
// Go back to the home route
|
||||||
|
this.router.navigateToRoute("")
|
||||||
|
}
|
||||||
|
|
||||||
|
public isAuthenticated(): boolean {
|
||||||
|
// Check whether the current time is past the
|
||||||
|
// access token's expiry time
|
||||||
|
const expiresAt = JSON.parse(localStorage.getItem('expires_at'))
|
||||||
|
return new Date().getTime() < expiresAt
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(private ea: EventAggregator, private http: HttpClient) {
|
||||||
this.ea.subscribe(PageTitle, msg => this.pageTitle = msg.title)
|
this.ea.subscribe(PageTitle, msg => this.pageTitle = msg.title)
|
||||||
|
var self = this
|
||||||
|
this.lock.on('authenticated', (authResult) => {
|
||||||
|
if (authResult && authResult.accessToken && authResult.idToken) {
|
||||||
|
this.setSession(authResult)
|
||||||
|
this.router.navigateToRoute("")
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.lock.on('authorization_error', (err) => {
|
||||||
|
this.router.navigateToRoute("")
|
||||||
|
console.log(err)
|
||||||
|
alert(`Error: ${err.error}. Check the console for further details.`)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
configureRouter(config: RouterConfiguration, router: Router){
|
configureRouter(config: RouterConfiguration, router: Router){
|
||||||
@ -18,10 +68,13 @@ export class App {
|
|||||||
config.options.pushState = true
|
config.options.pushState = true
|
||||||
config.options.root = "/"
|
config.options.root = "/"
|
||||||
config.map([
|
config.map([
|
||||||
{ route: "", moduleId: "home", name: "home", title: "Welcome" },
|
{ route: "", moduleId: "home", name: "home", title: "Welcome" }
|
||||||
{ route: 'contacts/:id', moduleId: 'contact-detail', name:'contacts' }
|
|
||||||
])
|
])
|
||||||
|
|
||||||
this.router = router
|
this.router = router
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public logon() {
|
||||||
|
this.lock.show()
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,42 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="panel panel-primary">
|
|
||||||
<div class="panel-heading">
|
|
||||||
<h3 class="panel-title">Profile</h3>
|
|
||||||
</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
<form role="form" class="form-horizontal">
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="col-sm-2 control-label">First Name</label>
|
|
||||||
<div class="col-sm-10">
|
|
||||||
<input type="text" placeholder="first name" class="form-control" value.bind="contact.firstName">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="col-sm-2 control-label">Last Name</label>
|
|
||||||
<div class="col-sm-10">
|
|
||||||
<input type="text" placeholder="last name" class="form-control" value.bind="contact.lastName">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="col-sm-2 control-label">Email</label>
|
|
||||||
<div class="col-sm-10">
|
|
||||||
<input type="text" placeholder="email" class="form-control" value.bind="contact.email">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="col-sm-2 control-label">Phone Number</label>
|
|
||||||
<div class="col-sm-10">
|
|
||||||
<input type="text" placeholder="phone number" class="form-control" value.bind="contact.phoneNumber">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="button-bar">
|
|
||||||
<button class="btn btn-success" click.delegate="save()" disabled.bind="!canSave">Save</button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
@ -1,58 +0,0 @@
|
|||||||
import {inject} from 'aurelia-framework';
|
|
||||||
import {EventAggregator} from 'aurelia-event-aggregator';
|
|
||||||
import {WebAPI} from './web-api';
|
|
||||||
import {ContactUpdated,ContactViewed} from './messages';
|
|
||||||
import {areEqual} from './utility';
|
|
||||||
|
|
||||||
interface Contact {
|
|
||||||
firstName: string;
|
|
||||||
lastName: string;
|
|
||||||
email: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
@inject(WebAPI, EventAggregator)
|
|
||||||
export class ContactDetail {
|
|
||||||
routeConfig;
|
|
||||||
contact: Contact;
|
|
||||||
originalContact: Contact;
|
|
||||||
|
|
||||||
constructor(private api: WebAPI, private ea: EventAggregator) { }
|
|
||||||
|
|
||||||
activate(params, routeConfig) {
|
|
||||||
this.routeConfig = routeConfig;
|
|
||||||
|
|
||||||
return this.api.getContactDetails(params.id).then(contact => {
|
|
||||||
this.contact = <Contact>contact;
|
|
||||||
this.routeConfig.navModel.setTitle(this.contact.firstName);
|
|
||||||
this.originalContact = JSON.parse(JSON.stringify(this.contact));
|
|
||||||
this.ea.publish(new ContactViewed(this.contact));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
get canSave() {
|
|
||||||
return this.contact.firstName && this.contact.lastName && !this.api.isRequesting;
|
|
||||||
}
|
|
||||||
|
|
||||||
save() {
|
|
||||||
this.api.saveContact(this.contact).then(contact => {
|
|
||||||
this.contact = <Contact>contact;
|
|
||||||
this.routeConfig.navModel.setTitle(this.contact.firstName);
|
|
||||||
this.originalContact = JSON.parse(JSON.stringify(this.contact));
|
|
||||||
this.ea.publish(new ContactUpdated(this.contact));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
canDeactivate() {
|
|
||||||
if(!areEqual(this.originalContact, this.contact)){
|
|
||||||
let result = confirm('You have unsaved changes. Are you sure you wish to leave?');
|
|
||||||
|
|
||||||
if(!result) {
|
|
||||||
this.ea.publish(new ContactViewed(this.contact));
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="contact-list">
|
|
||||||
<ul class="list-group">
|
|
||||||
<li repeat.for="contact of contacts" class="list-group-item ${contact.id === $parent.selectedId ? 'active' : ''}">
|
|
||||||
<a route-href="route: contacts; params.bind: {id:contact.id}" click.delegate="$parent.select(contact)">
|
|
||||||
<h4 class="list-group-item-heading">${contact.firstName} ${contact.lastName}</h4>
|
|
||||||
<p class="list-group-item-text">${contact.email}</p>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
@ -1,28 +0,0 @@
|
|||||||
import {EventAggregator} from 'aurelia-event-aggregator';
|
|
||||||
import {WebAPI} from './web-api';
|
|
||||||
import {ContactUpdated, ContactViewed} from './messages';
|
|
||||||
import {inject} from 'aurelia-framework';
|
|
||||||
|
|
||||||
@inject(WebAPI, EventAggregator)
|
|
||||||
export class ContactList {
|
|
||||||
contacts;
|
|
||||||
selectedId = 0;
|
|
||||||
|
|
||||||
constructor(private api: WebAPI, ea: EventAggregator) {
|
|
||||||
ea.subscribe(ContactViewed, msg => this.select(msg.contact));
|
|
||||||
ea.subscribe(ContactUpdated, msg => {
|
|
||||||
let id = msg.contact.id;
|
|
||||||
let found = this.contacts.find(x => x.id == id);
|
|
||||||
Object.assign(found, msg.contact);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
created() {
|
|
||||||
this.api.getContactList().then(contacts => this.contacts = contacts);
|
|
||||||
}
|
|
||||||
|
|
||||||
select(contact) {
|
|
||||||
this.selectedId = contact.id;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +1,3 @@
|
|||||||
export class ContactUpdated {
|
|
||||||
constructor(public contact) { }
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ContactViewed {
|
|
||||||
constructor(public contact) { }
|
|
||||||
}
|
|
||||||
|
|
||||||
export class PageTitle {
|
export class PageTitle {
|
||||||
constructor(public title: string) { }
|
constructor(public title: string) { }
|
||||||
}
|
}
|
@ -1,96 +0,0 @@
|
|||||||
let latency = 200;
|
|
||||||
let id = 0;
|
|
||||||
|
|
||||||
function getId(){
|
|
||||||
return ++id;
|
|
||||||
}
|
|
||||||
|
|
||||||
let contacts = [
|
|
||||||
{
|
|
||||||
id:getId(),
|
|
||||||
firstName:'John',
|
|
||||||
lastName:'Tolkien',
|
|
||||||
email:'tolkien@inklings.com',
|
|
||||||
phoneNumber:'867-5309'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id:getId(),
|
|
||||||
firstName:'Clive',
|
|
||||||
lastName:'Lewis',
|
|
||||||
email:'lewis@inklings.com',
|
|
||||||
phoneNumber:'867-5309'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id:getId(),
|
|
||||||
firstName:'Owen',
|
|
||||||
lastName:'Barfield',
|
|
||||||
email:'barfield@inklings.com',
|
|
||||||
phoneNumber:'867-5309'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id:getId(),
|
|
||||||
firstName:'Charles',
|
|
||||||
lastName:'Williams',
|
|
||||||
email:'williams@inklings.com',
|
|
||||||
phoneNumber:'867-5309'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id:getId(),
|
|
||||||
firstName:'Roger',
|
|
||||||
lastName:'Green',
|
|
||||||
email:'green@inklings.com',
|
|
||||||
phoneNumber:'867-5309'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
export class WebAPI {
|
|
||||||
isRequesting = false;
|
|
||||||
|
|
||||||
getContactList(){
|
|
||||||
this.isRequesting = true;
|
|
||||||
return new Promise(resolve => {
|
|
||||||
setTimeout(() => {
|
|
||||||
let results = contacts.map(x => { return {
|
|
||||||
id:x.id,
|
|
||||||
firstName:x.firstName,
|
|
||||||
lastName:x.lastName,
|
|
||||||
email:x.email
|
|
||||||
}});
|
|
||||||
resolve(results);
|
|
||||||
this.isRequesting = false;
|
|
||||||
}, latency);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getContactDetails(id){
|
|
||||||
this.isRequesting = true;
|
|
||||||
return new Promise(resolve => {
|
|
||||||
setTimeout(() => {
|
|
||||||
let found = contacts.filter(x => x.id == id)[0];
|
|
||||||
resolve(JSON.parse(JSON.stringify(found)));
|
|
||||||
this.isRequesting = false;
|
|
||||||
}, latency);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
saveContact(contact){
|
|
||||||
this.isRequesting = true;
|
|
||||||
return new Promise(resolve => {
|
|
||||||
setTimeout(() => {
|
|
||||||
let instance = JSON.parse(JSON.stringify(contact));
|
|
||||||
let found = contacts.filter(x => x.id == contact.id)[0];
|
|
||||||
|
|
||||||
if(found){
|
|
||||||
let index = contacts.indexOf(found);
|
|
||||||
contacts[index] = instance;
|
|
||||||
}else{
|
|
||||||
instance.id = getId();
|
|
||||||
contacts.push(instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.isRequesting = false;
|
|
||||||
resolve(instance);
|
|
||||||
}, latency);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user