Huge repo reorganization
In no particular order... - Created projects using F# generator, using Paket and FAKE - Split "entities" into their own project, and created interface for data functions required on those entities - Renamed "data" project and used it as an implementation of data access - Created "logic" layer that takes the data interface, and does the non-persistence-related manipulation of items - Moved "web" project to "app", and modified Nancy modules to utilize Logic project and data interface instead of Data project and RethinkDB connection - Created test placeholder project; will be filling that out shortly (TAD?)
This commit is contained in:
parent
8194649018
commit
710004dfc4
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -21,6 +21,8 @@ bld/
|
|||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
[Bb]uild/
|
||||
[Dd]eploy/
|
||||
|
||||
# Visual Studio 2015 cache/options directory
|
||||
.vs/
|
||||
|
@ -241,7 +243,7 @@ FakesAssemblies/
|
|||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
**/.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
|
|
BIN
src/.paket/paket.bootstrapper.exe
Normal file
BIN
src/.paket/paket.bootstrapper.exe
Normal file
Binary file not shown.
|
@ -1,12 +1,13 @@
|
|||
namespace MyWebLog
|
||||
|
||||
open MyWebLog.Data.WebLog
|
||||
open MyWebLog.Data
|
||||
open MyWebLog.Entities
|
||||
open MyWebLog.Logic.WebLog
|
||||
open Nancy
|
||||
open RethinkDb.Driver.Net
|
||||
|
||||
/// Handle /admin routes
|
||||
type AdminModule(conn : IConnection) as this =
|
||||
type AdminModule(data : IMyWebLogData) as this =
|
||||
inherit NancyModule("/admin")
|
||||
|
||||
do
|
||||
|
@ -15,6 +16,6 @@ type AdminModule(conn : IConnection) as this =
|
|||
/// Admin dashboard
|
||||
member this.Dashboard () =
|
||||
this.RequiresAccessLevel AuthorizationLevel.Administrator
|
||||
let model = DashboardModel(this.Context, this.WebLog, findDashboardCounts conn this.WebLog.Id)
|
||||
model.PageTitle <- Resources.Dashboard
|
||||
let model = DashboardModel(this.Context, this.WebLog, findDashboardCounts data this.WebLog.Id)
|
||||
model.PageTitle <- Resources.Dashboard
|
||||
upcast this.View.["admin/dashboard", model]
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
open MyWebLog
|
||||
open MyWebLog.Data
|
||||
open MyWebLog.Data.SetUp
|
||||
open MyWebLog.Data.WebLog
|
||||
open MyWebLog.Data.RethinkDB
|
||||
open MyWebLog.Entities
|
||||
open MyWebLog.Logic.WebLog
|
||||
open Nancy
|
||||
open Nancy.Authentication.Forms
|
||||
open Nancy.Bootstrapper
|
||||
|
@ -13,6 +13,7 @@ open Nancy.Cryptography
|
|||
open Nancy.Owin
|
||||
open Nancy.Security
|
||||
open Nancy.Session.Persistable
|
||||
//open Nancy.Session.Relational
|
||||
open Nancy.Session.RethinkDb
|
||||
open Nancy.TinyIoc
|
||||
open Nancy.ViewEngines.SuperSimpleViewEngine
|
||||
|
@ -21,6 +22,7 @@ open RethinkDb.Driver.Net
|
|||
open Suave
|
||||
open Suave.Owin
|
||||
open System
|
||||
open System.Configuration
|
||||
open System.IO
|
||||
open System.Text.RegularExpressions
|
||||
|
||||
|
@ -28,9 +30,11 @@ open System.Text.RegularExpressions
|
|||
let cfg = try AppConfig.FromJson (System.IO.File.ReadAllText "config.json")
|
||||
with ex -> raise <| ApplicationException(Resources.ErrBadAppConfig, ex)
|
||||
|
||||
let data : IMyWebLogData = upcast RethinkMyWebLogData(cfg.DataConfig.Conn, cfg.DataConfig)
|
||||
|
||||
do
|
||||
startUpCheck cfg.DataConfig
|
||||
|
||||
data.SetUp ()
|
||||
|
||||
/// Support RESX lookup via the @Translate SSVE alias
|
||||
type TranslateTokenViewEngineMatcher() =
|
||||
static let regex = Regex("@Translate\.(?<TranslationKey>[a-zA-Z0-9-_]+);?", RegexOptions.Compiled)
|
||||
|
@ -83,10 +87,10 @@ type MyWebLogBootstrapper() =
|
|||
|
||||
override this.ApplicationStartup (container, pipelines) =
|
||||
base.ApplicationStartup (container, pipelines)
|
||||
// Data configuration (both config and the connection; Nancy modules just need the connection)
|
||||
// Application configuration
|
||||
container.Register<AppConfig>(cfg)
|
||||
|> ignore
|
||||
container.Register<IConnection>(cfg.DataConfig.Conn)
|
||||
container.Register<IMyWebLogData>(data)
|
||||
|> ignore
|
||||
// NodaTime
|
||||
container.Register<IClock>(SystemClock.Instance)
|
||||
|
@ -110,6 +114,7 @@ type MyWebLogBootstrapper() =
|
|||
// Sessions
|
||||
let sessions = RethinkDbSessionConfiguration(cfg.DataConfig.Conn)
|
||||
sessions.Database <- cfg.DataConfig.Database
|
||||
//let sessions = RelationalSessionConfiguration(ConfigurationManager.ConnectionStrings.["SessionStore"].ConnectionString)
|
||||
PersistableSessions.Enable (pipelines, sessions)
|
||||
()
|
||||
|
||||
|
@ -127,7 +132,7 @@ type RequestEnvironment() =
|
|||
member this.Initialize (pipelines, context) =
|
||||
let establishEnv (ctx : NancyContext) =
|
||||
ctx.Items.[Keys.RequestStart] <- DateTime.Now.Ticks
|
||||
match tryFindWebLogByUrlBase cfg.DataConfig.Conn ctx.Request.Url.HostName with
|
||||
match tryFindWebLogByUrlBase data ctx.Request.Url.HostName with
|
||||
| Some webLog -> ctx.Items.[Keys.WebLog] <- webLog
|
||||
| None -> // TODO: redirect to domain set up page
|
||||
ApplicationException (sprintf "%s %s" ctx.Request.Url.HostName Resources.ErrNotConfigured)
|
|
@ -1,6 +1,6 @@
|
|||
namespace MyWebLog
|
||||
|
||||
open MyWebLog.Data
|
||||
open MyWebLog.Data.RethinkDB
|
||||
open Newtonsoft.Json
|
||||
open System.Text
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
namespace MyWebLog
|
||||
|
||||
open MyWebLog.Data.Category
|
||||
open MyWebLog.Data
|
||||
open MyWebLog.Logic.Category
|
||||
open MyWebLog.Entities
|
||||
open Nancy
|
||||
open Nancy.ModelBinding
|
||||
|
@ -8,7 +9,7 @@ open Nancy.Security
|
|||
open RethinkDb.Driver.Net
|
||||
|
||||
/// Handle /category and /categories URLs
|
||||
type CategoryModule(conn : IConnection) as this =
|
||||
type CategoryModule(data : IMyWebLogData) as this =
|
||||
inherit NancyModule()
|
||||
|
||||
do
|
||||
|
@ -21,7 +22,7 @@ type CategoryModule(conn : IConnection) as this =
|
|||
member this.CategoryList () =
|
||||
this.RequiresAccessLevel AuthorizationLevel.Administrator
|
||||
let model = CategoryListModel(this.Context, this.WebLog,
|
||||
(getAllCategories conn this.WebLog.Id
|
||||
(findAllCategories data this.WebLog.Id
|
||||
|> List.map (fun cat -> IndentedCategory.Create cat (fun _ -> false))))
|
||||
upcast this.View.["/admin/category/list", model]
|
||||
|
||||
|
@ -31,13 +32,13 @@ type CategoryModule(conn : IConnection) as this =
|
|||
let catId = parameters.["id"].ToString ()
|
||||
match (match catId with
|
||||
| "new" -> Some Category.Empty
|
||||
| _ -> tryFindCategory conn this.WebLog.Id catId) with
|
||||
| _ -> tryFindCategory data this.WebLog.Id catId) with
|
||||
| Some cat -> let model = CategoryEditModel(this.Context, this.WebLog, cat)
|
||||
model.Categories <- getAllCategories conn this.WebLog.Id
|
||||
model.Categories <- findAllCategories data this.WebLog.Id
|
||||
|> List.map (fun cat -> IndentedCategory.Create cat
|
||||
(fun c -> c = defaultArg (fst cat).ParentId ""))
|
||||
upcast this.View.["admin/category/edit", model]
|
||||
| None -> this.NotFound ()
|
||||
| _ -> this.NotFound ()
|
||||
|
||||
/// Save a category
|
||||
member this.SaveCategory (parameters : DynamicDictionary) =
|
||||
|
@ -45,41 +46,43 @@ type CategoryModule(conn : IConnection) as this =
|
|||
this.RequiresAccessLevel AuthorizationLevel.Administrator
|
||||
let catId = parameters.["id"].ToString ()
|
||||
let form = this.Bind<CategoryForm> ()
|
||||
let oldCat = match catId with "new" -> Some Category.Empty | _ -> tryFindCategory conn this.WebLog.Id catId
|
||||
let oldCat = match catId with
|
||||
| "new" -> Some { Category.Empty with WebLogId = this.WebLog.Id }
|
||||
| _ -> tryFindCategory data this.WebLog.Id catId
|
||||
match oldCat with
|
||||
| Some old -> let cat = { old with Name = form.Name
|
||||
Slug = form.Slug
|
||||
Description = match form.Description with "" -> None | d -> Some d
|
||||
ParentId = match form.ParentId with "" -> None | p -> Some p }
|
||||
let newCatId = saveCategory conn this.WebLog.Id cat
|
||||
let newCatId = saveCategory data cat
|
||||
match old.ParentId = cat.ParentId with
|
||||
| true -> ()
|
||||
| _ -> match old.ParentId with
|
||||
| Some parentId -> removeCategoryFromParent conn this.WebLog.Id parentId newCatId
|
||||
| None -> ()
|
||||
| Some parentId -> removeCategoryFromParent data this.WebLog.Id parentId newCatId
|
||||
| _ -> ()
|
||||
match cat.ParentId with
|
||||
| Some parentId -> addCategoryToParent conn this.WebLog.Id parentId newCatId
|
||||
| None -> ()
|
||||
| Some parentId -> addCategoryToParent data this.WebLog.Id parentId newCatId
|
||||
| _ -> ()
|
||||
let model = MyWebLogModel(this.Context, this.WebLog)
|
||||
{ UserMessage.Empty with
|
||||
Level = Level.Info
|
||||
Message = System.String.Format
|
||||
(Resources.MsgCategoryEditSuccess,
|
||||
(match catId with | "new" -> Resources.Added | _ -> Resources.Updated)) }
|
||||
(match catId with "new" -> Resources.Added | _ -> Resources.Updated)) }
|
||||
|> model.AddMessage
|
||||
this.Redirect (sprintf "/category/%s/edit" newCatId) model
|
||||
| None -> this.NotFound ()
|
||||
| _ -> this.NotFound ()
|
||||
|
||||
/// Delete a category
|
||||
member this.DeleteCategory (parameters : DynamicDictionary) =
|
||||
this.ValidateCsrfToken ()
|
||||
this.RequiresAccessLevel AuthorizationLevel.Administrator
|
||||
let catId = parameters.["id"].ToString ()
|
||||
match tryFindCategory conn this.WebLog.Id catId with
|
||||
| Some cat -> deleteCategory conn cat
|
||||
match tryFindCategory data this.WebLog.Id catId with
|
||||
| Some cat -> deleteCategory data cat
|
||||
let model = MyWebLogModel(this.Context, this.WebLog)
|
||||
{ UserMessage.Empty with Level = Level.Info
|
||||
Message = System.String.Format(Resources.MsgCategoryDeleted, cat.Name) }
|
||||
|> model.AddMessage
|
||||
this.Redirect "/categories" model
|
||||
| None -> this.NotFound ()
|
||||
| _ -> this.NotFound ()
|
302
src/MyWebLog.App/MyWebLog.App.fsproj
Normal file
302
src/MyWebLog.App/MyWebLog.App.fsproj
Normal file
|
@ -0,0 +1,302 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>9cea3a8b-e8aa-44e6-9f5f-2095ceed54eb</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>MyWebLog.App</RootNamespace>
|
||||
<AssemblyName>MyWebLog.App</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<TargetFSharpCoreVersion>4.4.0.0</TargetFSharpCoreVersion>
|
||||
<Name>MyWebLog.App</Name>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<Tailcalls>false</Tailcalls>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<WarningLevel>3</WarningLevel>
|
||||
<DocumentationFile>bin\Debug\MyWebLog.App.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<Tailcalls>true</Tailcalls>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<WarningLevel>3</WarningLevel>
|
||||
<DocumentationFile>bin\Release\MyWebLog.App.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="mscorlib" />
|
||||
<Reference Include="FSharp.Core, Version=$(TargetFSharpCoreVersion), Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Numerics" />
|
||||
<Reference Include="System.ServiceModel" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AssemblyInfo.fs" />
|
||||
<Compile Include="Keys.fs" />
|
||||
<Compile Include="AppConfig.fs" />
|
||||
<Compile Include="ViewModels.fs" />
|
||||
<Compile Include="ModuleExtensions.fs" />
|
||||
<Compile Include="AdminModule.fs" />
|
||||
<Compile Include="CategoryModule.fs" />
|
||||
<Compile Include="PageModule.fs" />
|
||||
<Compile Include="PostModule.fs" />
|
||||
<Compile Include="UserModule.fs" />
|
||||
<Compile Include="App.fs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MyWebLog.Data.RethinkDB\MyWebLog.Data.RethinkDB.fsproj">
|
||||
<Name>MyWebLog.Data.RethinkDB</Name>
|
||||
<Project>{d6c2be5e-883a-4f34-9905-b730543ca380}</Project>
|
||||
<Private>True</Private>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MyWebLog.Entities\MyWebLog.Entities.fsproj">
|
||||
<Name>MyWebLog.Entities</Name>
|
||||
<Project>{a87f3cf5-2189-442b-8acf-929f5153ac22}</Project>
|
||||
<Private>True</Private>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MyWebLog.Logic\MyWebLog.Logic.fsproj">
|
||||
<Name>MyWebLog.Logic</Name>
|
||||
<Project>{29f6eda3-4f43-4bb3-9c63-ae238a9b7f12}</Project>
|
||||
<Private>True</Private>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MyWebLog.Resources\MyWebLog.Resources.csproj">
|
||||
<Name>MyWebLog.Resources</Name>
|
||||
<Project>{a12ea8da-88bc-4447-90cb-a0e2dcc37523}</Project>
|
||||
<Private>True</Private>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<MinimumVisualStudioVersion Condition="'$(MinimumVisualStudioVersion)' == ''">11</MinimumVisualStudioVersion>
|
||||
</PropertyGroup>
|
||||
<Choose>
|
||||
<When Condition="'$(VisualStudioVersion)' == '11.0'">
|
||||
<PropertyGroup Condition="Exists('$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets')">
|
||||
<FSharpTargetsPath>$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets</FSharpTargetsPath>
|
||||
</PropertyGroup>
|
||||
</When>
|
||||
<Otherwise>
|
||||
<PropertyGroup Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets')">
|
||||
<FSharpTargetsPath>$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets</FSharpTargetsPath>
|
||||
</PropertyGroup>
|
||||
</Otherwise>
|
||||
</Choose>
|
||||
<Import Project="$(FSharpTargetsPath)" Condition="Exists('$(FSharpTargetsPath)')" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
<Choose>
|
||||
<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And ($(TargetFrameworkVersion) == 'v4.0' Or $(TargetFrameworkVersion) == 'v4.5' Or $(TargetFrameworkVersion) == 'v4.5.2')">
|
||||
<ItemGroup>
|
||||
<Reference Include="Common.Logging">
|
||||
<HintPath>..\packages\Common.Logging\lib\net40\Common.Logging.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Paket>True</Paket>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</When>
|
||||
</Choose>
|
||||
<Choose>
|
||||
<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And ($(TargetFrameworkVersion) == 'v4.0' Or $(TargetFrameworkVersion) == 'v4.5' Or $(TargetFrameworkVersion) == 'v4.5.2')">
|
||||
<ItemGroup>
|
||||
<Reference Include="Common.Logging.Core">
|
||||
<HintPath>..\packages\Common.Logging.Core\lib\net40\Common.Logging.Core.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Paket>True</Paket>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</When>
|
||||
</Choose>
|
||||
<Choose>
|
||||
<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And $(TargetFrameworkVersion) == 'v4.0'">
|
||||
<ItemGroup>
|
||||
<Reference Include="FSharp.Compiler.Service">
|
||||
<HintPath>..\packages\FSharp.Compiler.Service\lib\net40\FSharp.Compiler.Service.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Paket>True</Paket>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</When>
|
||||
<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And ($(TargetFrameworkVersion) == 'v4.5' Or $(TargetFrameworkVersion) == 'v4.5.2')">
|
||||
<ItemGroup>
|
||||
<Reference Include="FSharp.Compiler.Service">
|
||||
<HintPath>..\packages\FSharp.Compiler.Service\lib\net45\FSharp.Compiler.Service.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Paket>True</Paket>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</When>
|
||||
</Choose>
|
||||
<Choose>
|
||||
<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And ($(TargetFrameworkVersion) == 'v4.0' Or $(TargetFrameworkVersion) == 'v4.5' Or $(TargetFrameworkVersion) == 'v4.5.2')">
|
||||
<ItemGroup>
|
||||
<Reference Include="CSharpFormat">
|
||||
<HintPath>..\packages\FSharp.Formatting\lib\net40\CSharpFormat.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Paket>True</Paket>
|
||||
</Reference>
|
||||
<Reference Include="FSharp.CodeFormat">
|
||||
<HintPath>..\packages\FSharp.Formatting\lib\net40\FSharp.CodeFormat.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Paket>True</Paket>
|
||||
</Reference>
|
||||
<Reference Include="FSharp.Formatting.Common">
|
||||
<HintPath>..\packages\FSharp.Formatting\lib\net40\FSharp.Formatting.Common.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Paket>True</Paket>
|
||||
</Reference>
|
||||
<Reference Include="FSharp.Literate">
|
||||
<HintPath>..\packages\FSharp.Formatting\lib\net40\FSharp.Literate.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Paket>True</Paket>
|
||||
</Reference>
|
||||
<Reference Include="FSharp.Markdown">
|
||||
<HintPath>..\packages\FSharp.Formatting\lib\net40\FSharp.Markdown.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Paket>True</Paket>
|
||||
</Reference>
|
||||
<Reference Include="FSharp.MetadataFormat">
|
||||
<HintPath>..\packages\FSharp.Formatting\lib\net40\FSharp.MetadataFormat.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Paket>True</Paket>
|
||||
</Reference>
|
||||
<Reference Include="RazorEngine">
|
||||
<HintPath>..\packages\FSharp.Formatting\lib\net40\RazorEngine.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Paket>True</Paket>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Razor">
|
||||
<HintPath>..\packages\FSharp.Formatting\lib\net40\System.Web.Razor.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Paket>True</Paket>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</When>
|
||||
</Choose>
|
||||
<Choose>
|
||||
<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And ($(TargetFrameworkVersion) == 'v4.5' Or $(TargetFrameworkVersion) == 'v4.5.2')">
|
||||
<ItemGroup>
|
||||
<Reference Include="FSharpVSPowerTools.Core">
|
||||
<HintPath>..\packages\FSharpVSPowerTools.Core\lib\net45\FSharpVSPowerTools.Core.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Paket>True</Paket>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</When>
|
||||
</Choose>
|
||||
<Choose>
|
||||
<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And ($(TargetFrameworkVersion) == 'v4.0' Or $(TargetFrameworkVersion) == 'v4.5' Or $(TargetFrameworkVersion) == 'v4.5.2')">
|
||||
<ItemGroup>
|
||||
<Reference Include="Nancy">
|
||||
<HintPath>..\packages\Nancy\lib\net40\Nancy.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Paket>True</Paket>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</When>
|
||||
</Choose>
|
||||
<Choose>
|
||||
<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And ($(TargetFrameworkVersion) == 'v4.0' Or $(TargetFrameworkVersion) == 'v4.5' Or $(TargetFrameworkVersion) == 'v4.5.2')">
|
||||
<ItemGroup>
|
||||
<Reference Include="Nancy.Authentication.Forms">
|
||||
<HintPath>..\packages\Nancy.Authentication.Forms\lib\net40\Nancy.Authentication.Forms.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Paket>True</Paket>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</When>
|
||||
</Choose>
|
||||
<Choose>
|
||||
<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And $(TargetFrameworkVersion) == 'v4.5.2'">
|
||||
<ItemGroup>
|
||||
<Reference Include="Nancy.Session.Persistable">
|
||||
<HintPath>..\packages\Nancy.Session.Persistable\lib\net452\Nancy.Session.Persistable.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Paket>True</Paket>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</When>
|
||||
</Choose>
|
||||
<Choose>
|
||||
<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And $(TargetFrameworkVersion) == 'v4.5.2'">
|
||||
<ItemGroup>
|
||||
<Reference Include="Nancy.Session.RethinkDb">
|
||||
<HintPath>..\packages\Nancy.Session.RethinkDB\lib\net452\Nancy.Session.RethinkDb.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Paket>True</Paket>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</When>
|
||||
</Choose>
|
||||
<Choose>
|
||||
<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And $(TargetFrameworkVersion) == 'v4.0'">
|
||||
<ItemGroup>
|
||||
<Reference Include="Newtonsoft.Json">
|
||||
<HintPath>..\packages\Newtonsoft.Json\lib\net40\Newtonsoft.Json.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Paket>True</Paket>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</When>
|
||||
<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And ($(TargetFrameworkVersion) == 'v4.5' Or $(TargetFrameworkVersion) == 'v4.5.2')">
|
||||
<ItemGroup>
|
||||
<Reference Include="Newtonsoft.Json">
|
||||
<HintPath>..\packages\Newtonsoft.Json\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Paket>True</Paket>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</When>
|
||||
</Choose>
|
||||
<Choose>
|
||||
<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And ($(TargetFrameworkVersion) == 'v4.0' Or $(TargetFrameworkVersion) == 'v4.5' Or $(TargetFrameworkVersion) == 'v4.5.2')">
|
||||
<ItemGroup>
|
||||
<Reference Include="NodaTime">
|
||||
<HintPath>..\packages\NodaTime\lib\net35-Client\NodaTime.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Paket>True</Paket>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml">
|
||||
<Paket>True</Paket>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</When>
|
||||
</Choose>
|
||||
<Choose>
|
||||
<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And ($(TargetFrameworkVersion) == 'v4.5' Or $(TargetFrameworkVersion) == 'v4.5.2')">
|
||||
<ItemGroup>
|
||||
<Reference Include="RethinkDb.Driver">
|
||||
<HintPath>..\packages\RethinkDb.Driver\lib\net45\RethinkDb.Driver.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Paket>True</Paket>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</When>
|
||||
</Choose>
|
||||
<Choose>
|
||||
<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And ($(TargetFrameworkVersion) == 'v4.0' Or $(TargetFrameworkVersion) == 'v4.5' Or $(TargetFrameworkVersion) == 'v4.5.2')">
|
||||
<ItemGroup>
|
||||
<Reference Include="Suave">
|
||||
<HintPath>..\packages\Suave\lib\net40\Suave.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Paket>True</Paket>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</When>
|
||||
</Choose>
|
||||
</Project>
|
|
@ -1,8 +1,9 @@
|
|||
namespace MyWebLog
|
||||
|
||||
open FSharp.Markdown
|
||||
open MyWebLog.Data.Page
|
||||
open MyWebLog.Data
|
||||
open MyWebLog.Entities
|
||||
open MyWebLog.Logic.Page
|
||||
open Nancy
|
||||
open Nancy.ModelBinding
|
||||
open Nancy.Security
|
||||
|
@ -10,7 +11,7 @@ open NodaTime
|
|||
open RethinkDb.Driver.Net
|
||||
|
||||
/// Handle /pages and /page URLs
|
||||
type PageModule(conn : IConnection, clock : IClock) as this =
|
||||
type PageModule(data : IMyWebLogData, clock : IClock) as this =
|
||||
inherit NancyModule()
|
||||
|
||||
do
|
||||
|
@ -22,7 +23,7 @@ type PageModule(conn : IConnection, clock : IClock) as this =
|
|||
/// List all pages
|
||||
member this.PageList () =
|
||||
this.RequiresAccessLevel AuthorizationLevel.Administrator
|
||||
let model = PagesModel(this.Context, this.WebLog, (findAllPages conn this.WebLog.Id
|
||||
let model = PagesModel(this.Context, this.WebLog, (findAllPages data this.WebLog.Id
|
||||
|> List.map (fun p -> PageForDisplay(this.WebLog, p))))
|
||||
model.PageTitle <- Resources.Pages
|
||||
upcast this.View.["admin/page/list", model]
|
||||
|
@ -33,16 +34,16 @@ type PageModule(conn : IConnection, clock : IClock) as this =
|
|||
let pageId = parameters.["id"].ToString ()
|
||||
match (match pageId with
|
||||
| "new" -> Some Page.Empty
|
||||
| _ -> tryFindPage conn this.WebLog.Id pageId) with
|
||||
| _ -> tryFindPage data this.WebLog.Id pageId) with
|
||||
| Some page -> let rev = match page.Revisions
|
||||
|> List.sortByDescending (fun r -> r.AsOf)
|
||||
|> List.tryHead with
|
||||
| Some r -> r
|
||||
| None -> Revision.Empty
|
||||
| _ -> Revision.Empty
|
||||
let model = EditPageModel(this.Context, this.WebLog, page, rev)
|
||||
model.PageTitle <- match pageId with "new" -> Resources.AddNewPage | _ -> Resources.EditPage
|
||||
upcast this.View.["admin/page/edit", model]
|
||||
| None -> this.NotFound ()
|
||||
| _ -> this.NotFound ()
|
||||
|
||||
/// Save a page
|
||||
member this.SavePage (parameters : DynamicDictionary) =
|
||||
|
@ -51,7 +52,7 @@ type PageModule(conn : IConnection, clock : IClock) as this =
|
|||
let pageId = parameters.["id"].ToString ()
|
||||
let form = this.Bind<EditPageForm> ()
|
||||
let now = clock.Now.Ticks
|
||||
match (match pageId with "new" -> Some Page.Empty | _ -> tryFindPage conn this.WebLog.Id pageId) with
|
||||
match (match pageId with "new" -> Some Page.Empty | _ -> tryFindPage data this.WebLog.Id pageId) with
|
||||
| Some p -> let page = match pageId with "new" -> { p with WebLogId = this.WebLog.Id } | _ -> p
|
||||
let pId = { p with
|
||||
Title = form.Title
|
||||
|
@ -64,7 +65,7 @@ type PageModule(conn : IConnection, clock : IClock) as this =
|
|||
Revisions = { AsOf = now
|
||||
SourceType = form.Source
|
||||
Text = form.Text } :: page.Revisions }
|
||||
|> savePage conn
|
||||
|> savePage data
|
||||
let model = MyWebLogModel(this.Context, this.WebLog)
|
||||
{ UserMessage.Empty with
|
||||
Level = Level.Info
|
||||
|
@ -73,18 +74,18 @@ type PageModule(conn : IConnection, clock : IClock) as this =
|
|||
(match pageId with "new" -> Resources.Added | _ -> Resources.Updated)) }
|
||||
|> model.AddMessage
|
||||
this.Redirect (sprintf "/page/%s/edit" pId) model
|
||||
| None -> this.NotFound ()
|
||||
| _ -> this.NotFound ()
|
||||
|
||||
/// Delete a page
|
||||
member this.DeletePage (parameters : DynamicDictionary) =
|
||||
this.ValidateCsrfToken ()
|
||||
this.RequiresAccessLevel AuthorizationLevel.Administrator
|
||||
let pageId = parameters.["id"].ToString ()
|
||||
match tryFindPageWithoutRevisions conn this.WebLog.Id pageId with
|
||||
| Some page -> deletePage conn page.WebLogId page.Id
|
||||
match tryFindPageWithoutRevisions data this.WebLog.Id pageId with
|
||||
| Some page -> deletePage data page.WebLogId page.Id
|
||||
let model = MyWebLogModel(this.Context, this.WebLog)
|
||||
{ UserMessage.Empty with Level = Level.Info
|
||||
Message = Resources.MsgPageDeleted }
|
||||
|> model.AddMessage
|
||||
this.Redirect "/pages" model
|
||||
| None -> this.NotFound ()
|
||||
| _ -> this.NotFound ()
|
|
@ -1,10 +1,11 @@
|
|||
namespace MyWebLog
|
||||
|
||||
open FSharp.Markdown
|
||||
open MyWebLog.Data.Category
|
||||
open MyWebLog.Data.Page
|
||||
open MyWebLog.Data.Post
|
||||
open MyWebLog.Data
|
||||
open MyWebLog.Entities
|
||||
open MyWebLog.Logic.Category
|
||||
open MyWebLog.Logic.Page
|
||||
open MyWebLog.Logic.Post
|
||||
open Nancy
|
||||
open Nancy.ModelBinding
|
||||
open Nancy.Security
|
||||
|
@ -15,7 +16,7 @@ open System
|
|||
open System.ServiceModel.Syndication
|
||||
|
||||
/// Routes dealing with posts (including the home page, /tag, /category, RSS, and catch-all routes)
|
||||
type PostModule(conn : IConnection, clock : IClock) as this =
|
||||
type PostModule(data : IMyWebLogData, clock : IClock) as this =
|
||||
inherit NancyModule()
|
||||
|
||||
/// Get the page number from the dictionary
|
||||
|
@ -27,14 +28,14 @@ type PostModule(conn : IConnection, clock : IClock) as this =
|
|||
|
||||
/// Generate an RSS/Atom feed of the latest posts
|
||||
let generateFeed format : obj =
|
||||
let posts = findFeedPosts conn this.WebLog.Id 10
|
||||
let posts = findFeedPosts data this.WebLog.Id 10
|
||||
let feed =
|
||||
SyndicationFeed(
|
||||
this.WebLog.Name, defaultArg this.WebLog.Subtitle null,
|
||||
Uri(sprintf "%s://%s" this.Request.Url.Scheme this.WebLog.UrlBase), null,
|
||||
(match posts |> List.tryHead with
|
||||
| Some (post, _) -> Instant(post.UpdatedOn).ToDateTimeOffset ()
|
||||
| _ -> System.DateTimeOffset(System.DateTime.MinValue)),
|
||||
| _ -> System.DateTimeOffset(System.DateTime.MinValue)),
|
||||
posts
|
||||
|> List.map (fun (post, user) ->
|
||||
let item =
|
||||
|
@ -76,15 +77,15 @@ type PostModule(conn : IConnection, clock : IClock) as this =
|
|||
member this.PublishedPostsPage pageNbr =
|
||||
let model = PostsModel(this.Context, this.WebLog)
|
||||
model.PageNbr <- pageNbr
|
||||
model.Posts <- findPageOfPublishedPosts conn this.WebLog.Id pageNbr 10 |> forDisplay
|
||||
model.Posts <- findPageOfPublishedPosts data this.WebLog.Id pageNbr 10 |> forDisplay
|
||||
model.HasNewer <- match pageNbr with
|
||||
| 1 -> false
|
||||
| _ -> match List.isEmpty model.Posts with
|
||||
| true -> false
|
||||
| _ -> Option.isSome <| tryFindNewerPost conn (List.last model.Posts).Post
|
||||
| _ -> Option.isSome <| tryFindNewerPost data (List.last model.Posts).Post
|
||||
model.HasOlder <- match List.isEmpty model.Posts with
|
||||
| true -> false
|
||||
| _ -> Option.isSome <| tryFindOlderPost conn (List.head model.Posts).Post
|
||||
| _ -> Option.isSome <| tryFindOlderPost data (List.head model.Posts).Post
|
||||
model.UrlPrefix <- "/posts"
|
||||
model.PageTitle <- match pageNbr with 1 -> "" | _ -> sprintf "%s%i" Resources.PageHash pageNbr
|
||||
this.ThemedView "index" model
|
||||
|
@ -93,59 +94,59 @@ type PostModule(conn : IConnection, clock : IClock) as this =
|
|||
member this.HomePage () =
|
||||
match this.WebLog.DefaultPage with
|
||||
| "posts" -> this.PublishedPostsPage 1
|
||||
| pageId -> match tryFindPageWithoutRevisions conn this.WebLog.Id pageId with
|
||||
| pageId -> match tryFindPageWithoutRevisions data this.WebLog.Id pageId with
|
||||
| Some page -> let model = PageModel(this.Context, this.WebLog, page)
|
||||
model.PageTitle <- page.Title
|
||||
this.ThemedView "page" model
|
||||
| None -> this.NotFound ()
|
||||
| _ -> this.NotFound ()
|
||||
|
||||
/// Derive a post or page from the URL, or redirect from a prior URL to the current one
|
||||
member this.CatchAll (parameters : DynamicDictionary) =
|
||||
let url = parameters.["permalink"].ToString ()
|
||||
match tryFindPostByPermalink conn this.WebLog.Id url with
|
||||
match tryFindPostByPermalink data this.WebLog.Id url with
|
||||
| Some post -> // Hopefully the most common result; the permalink is a permalink!
|
||||
let model = PostModel(this.Context, this.WebLog, post)
|
||||
model.NewerPost <- tryFindNewerPost conn post
|
||||
model.OlderPost <- tryFindOlderPost conn post
|
||||
model.NewerPost <- tryFindNewerPost data post
|
||||
model.OlderPost <- tryFindOlderPost data post
|
||||
model.PageTitle <- post.Title
|
||||
this.ThemedView "single" model
|
||||
| None -> // Maybe it's a page permalink instead...
|
||||
match tryFindPageByPermalink conn this.WebLog.Id url with
|
||||
| Some page -> // ...and it is!
|
||||
let model = PageModel(this.Context, this.WebLog, page)
|
||||
model.PageTitle <- page.Title
|
||||
this.ThemedView "page" model
|
||||
| None -> // Maybe it's an old permalink for a post
|
||||
match tryFindPostByPriorPermalink conn this.WebLog.Id url with
|
||||
| Some post -> // Redirect them to the proper permalink
|
||||
upcast this.Response.AsRedirect(sprintf "/%s" post.Permalink)
|
||||
.WithStatusCode HttpStatusCode.MovedPermanently
|
||||
| None -> this.NotFound ()
|
||||
| _ -> // Maybe it's a page permalink instead...
|
||||
match tryFindPageByPermalink data this.WebLog.Id url with
|
||||
| Some page -> // ...and it is!
|
||||
let model = PageModel(this.Context, this.WebLog, page)
|
||||
model.PageTitle <- page.Title
|
||||
this.ThemedView "page" model
|
||||
| _ -> // Maybe it's an old permalink for a post
|
||||
match tryFindPostByPriorPermalink data this.WebLog.Id url with
|
||||
| Some post -> // Redirect them to the proper permalink
|
||||
upcast this.Response.AsRedirect(sprintf "/%s" post.Permalink)
|
||||
.WithStatusCode HttpStatusCode.MovedPermanently
|
||||
| _ -> this.NotFound ()
|
||||
|
||||
/// Display categorized posts
|
||||
member this.CategorizedPosts (parameters : DynamicDictionary) =
|
||||
let slug = parameters.["slug"].ToString ()
|
||||
match tryFindCategoryBySlug conn this.WebLog.Id slug with
|
||||
match tryFindCategoryBySlug data this.WebLog.Id slug with
|
||||
| Some cat -> let pageNbr = getPage parameters
|
||||
let model = PostsModel(this.Context, this.WebLog)
|
||||
model.PageNbr <- pageNbr
|
||||
model.Posts <- findPageOfCategorizedPosts conn this.WebLog.Id cat.Id pageNbr 10 |> forDisplay
|
||||
model.Posts <- findPageOfCategorizedPosts data this.WebLog.Id cat.Id pageNbr 10 |> forDisplay
|
||||
model.HasNewer <- match List.isEmpty model.Posts with
|
||||
| true -> false
|
||||
| _ -> Option.isSome <| tryFindNewerCategorizedPost conn cat.Id
|
||||
| _ -> Option.isSome <| tryFindNewerCategorizedPost data cat.Id
|
||||
(List.head model.Posts).Post
|
||||
model.HasOlder <- match List.isEmpty model.Posts with
|
||||
| true -> false
|
||||
| _ -> Option.isSome <| tryFindOlderCategorizedPost conn cat.Id
|
||||
| _ -> Option.isSome <| tryFindOlderCategorizedPost data cat.Id
|
||||
(List.last model.Posts).Post
|
||||
model.UrlPrefix <- sprintf "/category/%s" slug
|
||||
model.PageTitle <- sprintf "\"%s\" Category%s" cat.Name
|
||||
(match pageNbr with | 1 -> "" | n -> sprintf " | Page %i" n)
|
||||
model.Subtitle <- Some <| match cat.Description with
|
||||
| Some desc -> desc
|
||||
| None -> sprintf "Posts in the \"%s\" category" cat.Name
|
||||
| _ -> sprintf "Posts in the \"%s\" category" cat.Name
|
||||
this.ThemedView "index" model
|
||||
| None -> this.NotFound ()
|
||||
| _ -> this.NotFound ()
|
||||
|
||||
/// Display tagged posts
|
||||
member this.TaggedPosts (parameters : DynamicDictionary) =
|
||||
|
@ -153,13 +154,13 @@ type PostModule(conn : IConnection, clock : IClock) as this =
|
|||
let pageNbr = getPage parameters
|
||||
let model = PostsModel(this.Context, this.WebLog)
|
||||
model.PageNbr <- pageNbr
|
||||
model.Posts <- findPageOfTaggedPosts conn this.WebLog.Id tag pageNbr 10 |> forDisplay
|
||||
model.Posts <- findPageOfTaggedPosts data this.WebLog.Id tag pageNbr 10 |> forDisplay
|
||||
model.HasNewer <- match List.isEmpty model.Posts with
|
||||
| true -> false
|
||||
| _ -> Option.isSome <| tryFindNewerTaggedPost conn tag (List.head model.Posts).Post
|
||||
| _ -> Option.isSome <| tryFindNewerTaggedPost data tag (List.head model.Posts).Post
|
||||
model.HasOlder <- match List.isEmpty model.Posts with
|
||||
| true -> false
|
||||
| _ -> Option.isSome <| tryFindOlderTaggedPost conn tag (List.last model.Posts).Post
|
||||
| _ -> Option.isSome <| tryFindOlderTaggedPost data tag (List.last model.Posts).Post
|
||||
model.UrlPrefix <- sprintf "/tag/%s" tag
|
||||
model.PageTitle <- sprintf "\"%s\" Tag%s" tag (match pageNbr with 1 -> "" | n -> sprintf " | Page %i" n)
|
||||
model.Subtitle <- Some <| sprintf "Posts tagged \"%s\"" tag
|
||||
|
@ -182,7 +183,7 @@ type PostModule(conn : IConnection, clock : IClock) as this =
|
|||
this.RequiresAccessLevel AuthorizationLevel.Administrator
|
||||
let model = PostsModel(this.Context, this.WebLog)
|
||||
model.PageNbr <- pageNbr
|
||||
model.Posts <- findPageOfAllPosts conn this.WebLog.Id pageNbr 25 |> forDisplay
|
||||
model.Posts <- findPageOfAllPosts data this.WebLog.Id pageNbr 25 |> forDisplay
|
||||
model.HasNewer <- pageNbr > 1
|
||||
model.HasOlder <- List.length model.Posts > 24
|
||||
model.UrlPrefix <- "/posts/list"
|
||||
|
@ -193,21 +194,21 @@ type PostModule(conn : IConnection, clock : IClock) as this =
|
|||
member this.EditPost (parameters : DynamicDictionary) =
|
||||
this.RequiresAccessLevel AuthorizationLevel.Administrator
|
||||
let postId = parameters.["postId"].ToString ()
|
||||
match (match postId with "new" -> Some Post.Empty | _ -> tryFindPost conn this.WebLog.Id postId) with
|
||||
match (match postId with "new" -> Some Post.Empty | _ -> tryFindPost data this.WebLog.Id postId) with
|
||||
| Some post -> let rev = match post.Revisions
|
||||
|> List.sortByDescending (fun r -> r.AsOf)
|
||||
|> List.tryHead with
|
||||
| Some r -> r
|
||||
| None -> Revision.Empty
|
||||
let model = EditPostModel(this.Context, this.WebLog, post, rev)
|
||||
model.Categories <- getAllCategories conn this.WebLog.Id
|
||||
model.Categories <- findAllCategories data this.WebLog.Id
|
||||
|> List.map (fun cat -> string (fst cat).Id,
|
||||
sprintf "%s%s"
|
||||
(String.replicate (snd cat) " ")
|
||||
(fst cat).Name)
|
||||
model.PageTitle <- match post.Id with "new" -> Resources.AddNewPost | _ -> Resources.EditPost
|
||||
upcast this.View.["admin/post/edit"]
|
||||
| None -> this.NotFound ()
|
||||
| _ -> this.NotFound ()
|
||||
|
||||
/// Save a post
|
||||
member this.SavePost (parameters : DynamicDictionary) =
|
||||
|
@ -216,7 +217,7 @@ type PostModule(conn : IConnection, clock : IClock) as this =
|
|||
let postId = parameters.["postId"].ToString ()
|
||||
let form = this.Bind<EditPostForm>()
|
||||
let now = clock.Now.Ticks
|
||||
match (match postId with "new" -> Some Post.Empty | _ -> tryFindPost conn this.WebLog.Id postId) with
|
||||
match (match postId with "new" -> Some Post.Empty | _ -> tryFindPost data this.WebLog.Id postId) with
|
||||
| Some p -> let justPublished = p.PublishedOn = int64 0 && form.PublishNow
|
||||
let post = match postId with
|
||||
| "new" -> { p with
|
||||
|
@ -242,14 +243,14 @@ type PostModule(conn : IConnection, clock : IClock) as this =
|
|||
Revisions = { AsOf = now
|
||||
SourceType = form.Source
|
||||
Text = form.Text } :: post.Revisions }
|
||||
|> savePost conn
|
||||
|> savePost data
|
||||
let model = MyWebLogModel(this.Context, this.WebLog)
|
||||
{ UserMessage.Empty with
|
||||
Level = Level.Info
|
||||
Message = System.String.Format
|
||||
(Resources.MsgPostEditSuccess,
|
||||
(match postId with | "new" -> Resources.Added | _ -> Resources.Updated),
|
||||
(match justPublished with | true -> Resources.AndPublished | _ -> "")) }
|
||||
(match postId with "new" -> Resources.Added | _ -> Resources.Updated),
|
||||
(match justPublished with true -> Resources.AndPublished | _ -> "")) }
|
||||
|> model.AddMessage
|
||||
this.Redirect (sprintf "/post/%s/edit" pId) model
|
||||
| None -> this.NotFound ()
|
||||
| _ -> this.NotFound ()
|
|
@ -1,7 +1,8 @@
|
|||
namespace MyWebLog
|
||||
|
||||
open MyWebLog.Data.User
|
||||
open MyWebLog.Data
|
||||
open MyWebLog.Entities
|
||||
open MyWebLog.Logic.User
|
||||
open Nancy
|
||||
open Nancy.Authentication.Forms
|
||||
open Nancy.Cryptography
|
||||
|
@ -12,7 +13,7 @@ open RethinkDb.Driver.Net
|
|||
open System.Text
|
||||
|
||||
/// Handle /user URLs
|
||||
type UserModule(conn : IConnection, cfg : AppConfig) as this =
|
||||
type UserModule(data : IMyWebLogData, cfg : AppConfig) as this =
|
||||
inherit NancyModule("/user")
|
||||
|
||||
/// Hash the user's password
|
||||
|
@ -37,7 +38,7 @@ type UserModule(conn : IConnection, cfg : AppConfig) as this =
|
|||
this.ValidateCsrfToken ()
|
||||
let form = this.Bind<LogOnForm> ()
|
||||
let model = MyWebLogModel(this.Context, this.WebLog)
|
||||
match tryUserLogOn conn form.Email (pbkdf2 form.Password) with
|
||||
match tryUserLogOn data form.Email (pbkdf2 form.Password) with
|
||||
| Some user -> this.Session.[Keys.User] <- user
|
||||
{ UserMessage.Empty with Level = Level.Info
|
||||
Message = Resources.MsgLogOnSuccess }
|
||||
|
@ -46,10 +47,10 @@ type UserModule(conn : IConnection, cfg : AppConfig) as this =
|
|||
// TODO: investigate if addMessage should update the session when it's called
|
||||
upcast this.LoginAndRedirect (System.Guid.Parse user.Id,
|
||||
fallbackRedirectUrl = defaultArg (Option.ofObj form.ReturnUrl) "/")
|
||||
| None -> { UserMessage.Empty with Level = Level.Error
|
||||
Message = Resources.ErrBadLogOnAttempt }
|
||||
|> model.AddMessage
|
||||
this.Redirect (sprintf "/user/logon?returnUrl=%s" form.ReturnUrl) model
|
||||
| _ -> { UserMessage.Empty with Level = Level.Error
|
||||
Message = Resources.ErrBadLogOnAttempt }
|
||||
|> model.AddMessage
|
||||
this.Redirect (sprintf "/user/logon?returnUrl=%s" form.ReturnUrl) model
|
||||
|
||||
/// Log a user off
|
||||
member this.LogOff () =
|
|
@ -1,7 +1,7 @@
|
|||
namespace MyWebLog
|
||||
|
||||
open MyWebLog.Data.WebLog
|
||||
open MyWebLog.Entities
|
||||
open MyWebLog.Logic.WebLog
|
||||
open Nancy
|
||||
open Nancy.Session.Persistable
|
||||
open Newtonsoft.Json
|
7
src/MyWebLog.App/paket.references
Normal file
7
src/MyWebLog.App/paket.references
Normal file
|
@ -0,0 +1,7 @@
|
|||
FSharp.Formatting
|
||||
Nancy
|
||||
Nancy.Authentication.Forms
|
||||
Nancy.Session.RethinkDB
|
||||
NodaTime
|
||||
RethinkDb.Driver
|
||||
Suave
|
|
@ -4,17 +4,17 @@ open System.Reflection
|
|||
open System.Runtime.CompilerServices
|
||||
open System.Runtime.InteropServices
|
||||
|
||||
[<assembly: AssemblyTitle("MyWebLog.Data")>]
|
||||
[<assembly: AssemblyDescription("Data access for myWebLog")>]
|
||||
[<assembly: AssemblyTitle("MyWebLog.Data.RethinkDB")>]
|
||||
[<assembly: AssemblyDescription("RethinkDB data access for myWebLog")>]
|
||||
[<assembly: AssemblyConfiguration("")>]
|
||||
[<assembly: AssemblyCompany("DJS Consulting")>]
|
||||
[<assembly: AssemblyProduct("MyWebLog.Data")>]
|
||||
[<assembly: AssemblyProduct("MyWebLog.Data.RethinkDB")>]
|
||||
[<assembly: AssemblyCopyright("Copyright © 2016")>]
|
||||
[<assembly: AssemblyTrademark("")>]
|
||||
[<assembly: AssemblyCulture("")>]
|
||||
[<assembly: ComVisible(false)>]
|
||||
[<assembly: Guid("1fba0b84-b09e-4b16-b9b6-5730dea27192")>]
|
||||
[<assembly: AssemblyVersion("0.9.1.0")>]
|
||||
[<assembly: AssemblyVersion("0.9.2.0")>]
|
||||
[<assembly: AssemblyFileVersion("1.0.0.0")>]
|
||||
|
||||
do
|
|
@ -1,8 +1,7 @@
|
|||
module MyWebLog.Data.Category
|
||||
module MyWebLog.Data.RethinkDB.Category
|
||||
|
||||
open FSharp.Interop.Dynamic
|
||||
open MyWebLog.Entities
|
||||
open Rethink
|
||||
open RethinkDb.Driver.Ast
|
||||
open System.Dynamic
|
||||
|
||||
|
@ -14,20 +13,6 @@ let private category (webLogId : string) (catId : string) =
|
|||
.Get(catId)
|
||||
.Filter(fun c -> c.["WebLogId"].Eq(webLogId))
|
||||
|
||||
/// Sort categories by their name, with their children sorted below them, including an indent level
|
||||
let sortCategories categories =
|
||||
let rec getChildren (cat : Category) indent =
|
||||
seq {
|
||||
yield cat, indent
|
||||
for child in categories |> List.filter (fun c -> c.ParentId = Some cat.Id) do
|
||||
yield! getChildren child (indent + 1)
|
||||
}
|
||||
categories
|
||||
|> List.filter (fun c -> c.ParentId.IsNone)
|
||||
|> List.map (fun c -> getChildren c 0)
|
||||
|> Seq.collect id
|
||||
|> Seq.toList
|
||||
|
||||
/// Get all categories for a web log
|
||||
let getAllCategories conn (webLogId : string) =
|
||||
r.Table(Table.Category)
|
||||
|
@ -36,7 +21,6 @@ let getAllCategories conn (webLogId : string) =
|
|||
.RunListAsync<Category>(conn)
|
||||
|> await
|
||||
|> Seq.toList
|
||||
|> sortCategories
|
||||
|
||||
/// Get a specific category by its Id
|
||||
let tryFindCategory conn webLogId catId : Category option =
|
||||
|
@ -45,52 +29,41 @@ let tryFindCategory conn webLogId catId : Category option =
|
|||
| null -> None
|
||||
| cat -> Some <| unbox cat
|
||||
|
||||
/// Save a category
|
||||
let saveCategory conn webLogId (cat : Category) =
|
||||
match cat.Id with
|
||||
| "new" -> let newCat = { cat with Id = string <| System.Guid.NewGuid()
|
||||
WebLogId = webLogId }
|
||||
r.Table(Table.Category)
|
||||
.Insert(newCat)
|
||||
.RunResultAsync(conn) |> await |> ignore
|
||||
newCat.Id
|
||||
| _ -> let upd8 = ExpandoObject()
|
||||
upd8?Name <- cat.Name
|
||||
upd8?Slug <- cat.Slug
|
||||
upd8?Description <- cat.Description
|
||||
upd8?ParentId <- cat.ParentId
|
||||
(category webLogId cat.Id)
|
||||
.Update(upd8)
|
||||
.RunResultAsync(conn) |> await |> ignore
|
||||
cat.Id
|
||||
/// Add a category
|
||||
let addCategory conn (cat : Category) =
|
||||
r.Table(Table.Category)
|
||||
.Insert(cat)
|
||||
.RunResultAsync(conn) |> await |> ignore
|
||||
|
||||
/// Remove a category from a given parent
|
||||
let removeCategoryFromParent conn webLogId parentId catId =
|
||||
match tryFindCategory conn webLogId parentId with
|
||||
| Some parent -> let upd8 = ExpandoObject()
|
||||
upd8?Children <- parent.Children
|
||||
|> List.filter (fun childId -> childId <> catId)
|
||||
(category webLogId parentId)
|
||||
.Update(upd8)
|
||||
.RunResultAsync(conn) |> await |> ignore
|
||||
| None -> ()
|
||||
/// Update a category
|
||||
let updateCategory conn (cat : Category) =
|
||||
let upd8 = ExpandoObject()
|
||||
upd8?Name <- cat.Name
|
||||
upd8?Slug <- cat.Slug
|
||||
upd8?Description <- cat.Description
|
||||
upd8?ParentId <- cat.ParentId
|
||||
(category cat.WebLogId cat.Id)
|
||||
.Update(upd8)
|
||||
.RunResultAsync(conn) |> await |> ignore
|
||||
|
||||
/// Add a category to a given parent
|
||||
let addCategoryToParent conn webLogId parentId catId =
|
||||
match tryFindCategory conn webLogId parentId with
|
||||
| Some parent -> let upd8 = ExpandoObject()
|
||||
upd8?Children <- catId :: parent.Children
|
||||
(category webLogId parentId)
|
||||
.Update(upd8)
|
||||
.RunResultAsync(conn) |> await |> ignore
|
||||
| None -> ()
|
||||
/// Update a category's children
|
||||
let updateChildren conn webLogId parentId (children : string list) =
|
||||
let upd8 = ExpandoObject()
|
||||
upd8?Children <- children
|
||||
(category webLogId parentId)
|
||||
.Update(upd8)
|
||||
.RunResultAsync(conn) |> await |> ignore
|
||||
|
||||
/// Delete a category
|
||||
let deleteCategory conn cat =
|
||||
// Remove the category from its parent
|
||||
match cat.ParentId with
|
||||
| Some parentId -> removeCategoryFromParent conn cat.WebLogId parentId cat.Id
|
||||
| None -> ()
|
||||
| Some parentId -> match tryFindCategory conn cat.WebLogId parentId with
|
||||
| Some parent -> parent.Children
|
||||
|> List.filter (fun childId -> childId <> cat.Id)
|
||||
|> updateChildren conn cat.WebLogId parentId
|
||||
| _ -> ()
|
||||
| _ -> ()
|
||||
// Move this category's children to its parent
|
||||
let newParent = ExpandoObject()
|
||||
newParent?ParentId <- cat.ParentId
|
|
@ -1,4 +1,4 @@
|
|||
namespace MyWebLog.Data
|
||||
namespace MyWebLog.Data.RethinkDB
|
||||
|
||||
open RethinkDb.Driver
|
||||
open RethinkDb.Driver.Net
|
|
@ -1,4 +1,5 @@
|
|||
module MyWebLog.Data.Rethink
|
||||
[<AutoOpen>]
|
||||
module MyWebLog.Data.RethinkDB.Extensions
|
||||
|
||||
open RethinkDb.Driver.Ast
|
||||
open RethinkDb.Driver.Net
|
161
src/MyWebLog.Data.RethinkDB/MyWebLog.Data.RethinkDB.fsproj
Normal file
161
src/MyWebLog.Data.RethinkDB/MyWebLog.Data.RethinkDB.fsproj
Normal file
|
@ -0,0 +1,161 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>d6c2be5e-883a-4f34-9905-b730543ca380</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>MyWebLog.Data.RethinkDB</RootNamespace>
|
||||
<AssemblyName>MyWebLog.Data.RethinkDB</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<TargetFSharpCoreVersion>4.4.0.0</TargetFSharpCoreVersion>
|
||||
<Name>MyWebLog.Data.RethinkDB</Name>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<Tailcalls>false</Tailcalls>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<WarningLevel>3</WarningLevel>
|
||||
<DocumentationFile>bin\Debug\MyWebLog.Data.RethinkDB.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<Tailcalls>true</Tailcalls>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<WarningLevel>3</WarningLevel>
|
||||
<DocumentationFile>bin\Release\MyWebLog.Data.RethinkDB.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="mscorlib" />
|
||||
<Reference Include="FSharp.Core, Version=$(TargetFSharpCoreVersion), Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Numerics" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Extensions.fs" />
|
||||
<Compile Include="Table.fs" />
|
||||
<Compile Include="DataConfig.fs" />
|
||||
<Compile Include="Category.fs" />
|
||||
<Compile Include="Page.fs" />
|
||||
<Compile Include="Post.fs" />
|
||||
<Compile Include="User.fs" />
|
||||
<Compile Include="WebLog.fs" />
|
||||
<Compile Include="SetUp.fs" />
|
||||
<Compile Include="RethinkMyWebLogData.fs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MyWebLog.Entities\MyWebLog.Entities.fsproj">
|
||||
<Name>MyWebLog.Entities</Name>
|
||||
<Project>{a87f3cf5-2189-442b-8acf-929f5153ac22}</Project>
|
||||
<Private>True</Private>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<MinimumVisualStudioVersion Condition="'$(MinimumVisualStudioVersion)' == ''">11</MinimumVisualStudioVersion>
|
||||
</PropertyGroup>
|
||||
<Choose>
|
||||
<When Condition="'$(VisualStudioVersion)' == '11.0'">
|
||||
<PropertyGroup Condition="Exists('$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets')">
|
||||
<FSharpTargetsPath>$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets</FSharpTargetsPath>
|
||||
</PropertyGroup>
|
||||
</When>
|
||||
<Otherwise>
|
||||
<PropertyGroup Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets')">
|
||||
<FSharpTargetsPath>$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets</FSharpTargetsPath>
|
||||
</PropertyGroup>
|
||||
</Otherwise>
|
||||
</Choose>
|
||||
<Import Project="$(FSharpTargetsPath)" Condition="Exists('$(FSharpTargetsPath)')" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
<Choose>
|
||||
<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And ($(TargetFrameworkVersion) == 'v4.0' Or $(TargetFrameworkVersion) == 'v4.5' Or $(TargetFrameworkVersion) == 'v4.5.2')">
|
||||
<ItemGroup>
|
||||
<Reference Include="Common.Logging">
|
||||
<HintPath>..\packages\Common.Logging\lib\net40\Common.Logging.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Paket>True</Paket>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</When>
|
||||
</Choose>
|
||||
<Choose>
|
||||
<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And ($(TargetFrameworkVersion) == 'v4.0' Or $(TargetFrameworkVersion) == 'v4.5' Or $(TargetFrameworkVersion) == 'v4.5.2')">
|
||||
<ItemGroup>
|
||||
<Reference Include="Common.Logging.Core">
|
||||
<HintPath>..\packages\Common.Logging.Core\lib\net40\Common.Logging.Core.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Paket>True</Paket>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</When>
|
||||
</Choose>
|
||||
<Choose>
|
||||
<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And ($(TargetFrameworkVersion) == 'v4.0' Or $(TargetFrameworkVersion) == 'v4.5' Or $(TargetFrameworkVersion) == 'v4.5.2')">
|
||||
<ItemGroup>
|
||||
<Reference Include="Dynamitey">
|
||||
<HintPath>..\packages\Dynamitey\lib\net40\Dynamitey.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Paket>True</Paket>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</When>
|
||||
</Choose>
|
||||
<Choose>
|
||||
<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And ($(TargetFrameworkVersion) == 'v4.5' Or $(TargetFrameworkVersion) == 'v4.5.2')">
|
||||
<ItemGroup>
|
||||
<Reference Include="FSharp.Interop.Dynamic">
|
||||
<HintPath>..\packages\FSharp.Interop.Dynamic\lib\portable-net45+sl50+win\FSharp.Interop.Dynamic.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Paket>True</Paket>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</When>
|
||||
</Choose>
|
||||
<Choose>
|
||||
<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And $(TargetFrameworkVersion) == 'v4.0'">
|
||||
<ItemGroup>
|
||||
<Reference Include="Newtonsoft.Json">
|
||||
<HintPath>..\packages\Newtonsoft.Json\lib\net40\Newtonsoft.Json.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Paket>True</Paket>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</When>
|
||||
<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And ($(TargetFrameworkVersion) == 'v4.5' Or $(TargetFrameworkVersion) == 'v4.5.2')">
|
||||
<ItemGroup>
|
||||
<Reference Include="Newtonsoft.Json">
|
||||
<HintPath>..\packages\Newtonsoft.Json\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Paket>True</Paket>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</When>
|
||||
</Choose>
|
||||
<Choose>
|
||||
<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And ($(TargetFrameworkVersion) == 'v4.5' Or $(TargetFrameworkVersion) == 'v4.5.2')">
|
||||
<ItemGroup>
|
||||
<Reference Include="RethinkDb.Driver">
|
||||
<HintPath>..\packages\RethinkDb.Driver\lib\net45\RethinkDb.Driver.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Paket>True</Paket>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</When>
|
||||
</Choose>
|
||||
</Project>
|
70
src/MyWebLog.Data.RethinkDB/Page.fs
Normal file
70
src/MyWebLog.Data.RethinkDB/Page.fs
Normal file
|
@ -0,0 +1,70 @@
|
|||
module MyWebLog.Data.RethinkDB.Page
|
||||
|
||||
open FSharp.Interop.Dynamic
|
||||
open MyWebLog.Entities
|
||||
open RethinkDb.Driver.Ast
|
||||
open System.Dynamic
|
||||
|
||||
let private r = RethinkDb.Driver.RethinkDB.R
|
||||
|
||||
/// Try to find a page by its Id, optionally including revisions
|
||||
let tryFindPageById conn webLogId (pageId : string) includeRevs =
|
||||
let pg = r.Table(Table.Page)
|
||||
.Get(pageId)
|
||||
match (match includeRevs with
|
||||
| true -> pg.RunAtomAsync<Page>(conn)
|
||||
| _ -> pg.Without("Revisions").RunAtomAsync<Page>(conn)
|
||||
|> await |> box) with
|
||||
| null -> None
|
||||
| page -> let pg : Page = unbox page
|
||||
match pg.WebLogId = webLogId with true -> Some pg | _ -> None
|
||||
|
||||
/// Find a page by its permalink
|
||||
let tryFindPageByPermalink conn (webLogId : string) (permalink : string) =
|
||||
r.Table(Table.Page)
|
||||
.GetAll(r.Array(webLogId, permalink)).OptArg("index", "Permalink")
|
||||
.Without("Revisions")
|
||||
.RunCursorAsync<Page>(conn)
|
||||
|> await
|
||||
|> Seq.tryHead
|
||||
|
||||
/// Get a list of all pages (excludes page text and revisions)
|
||||
let findAllPages conn (webLogId : string) =
|
||||
r.Table(Table.Page)
|
||||
.GetAll(webLogId).OptArg("index", "WebLogId")
|
||||
.OrderBy("Title")
|
||||
.Without("Text", "Revisions")
|
||||
.RunListAsync<Page>(conn)
|
||||
|> await
|
||||
|> Seq.toList
|
||||
|
||||
/// Add a page
|
||||
let addPage conn (page : Page) =
|
||||
r.Table(Table.Page)
|
||||
.Insert(page)
|
||||
.RunResultAsync(conn) |> await |> ignore
|
||||
|
||||
/// Update a page
|
||||
let updatePage conn (page : Page) =
|
||||
match tryFindPageById conn page.WebLogId page.Id false with
|
||||
| Some _ -> let upd8 = ExpandoObject()
|
||||
upd8?Title <- page.Title
|
||||
upd8?Permalink <- page.Permalink
|
||||
upd8?PublishedOn <- page.PublishedOn
|
||||
upd8?UpdatedOn <- page.UpdatedOn
|
||||
upd8?Text <- page.Text
|
||||
upd8?Revisions <- page.Revisions
|
||||
r.Table(Table.Page)
|
||||
.Get(page.Id)
|
||||
.Update(upd8)
|
||||
.RunResultAsync(conn) |> await |> ignore
|
||||
| _ -> ()
|
||||
|
||||
/// Delete a page
|
||||
let deletePage conn webLogId pageId =
|
||||
match tryFindPageById conn webLogId pageId false with
|
||||
| Some _ -> r.Table(Table.Page)
|
||||
.Get(pageId)
|
||||
.Delete()
|
||||
.RunResultAsync(conn) |> await |> ignore
|
||||
| _ -> ()
|
|
@ -1,8 +1,7 @@
|
|||
module MyWebLog.Data.Post
|
||||
module MyWebLog.Data.RethinkDB.Post
|
||||
|
||||
open FSharp.Interop.Dynamic
|
||||
open MyWebLog.Entities
|
||||
open Rethink
|
||||
open RethinkDb.Driver.Ast
|
||||
open System.Dynamic
|
||||
|
||||
|
@ -146,6 +145,22 @@ let findFeedPosts conn webLogId nbr : (Post * User option) list =
|
|||
| null -> None
|
||||
| user -> Some <| unbox user)
|
||||
|
||||
/// Add a post
|
||||
let addPost conn post =
|
||||
r.Table(Table.Post)
|
||||
.Insert(post)
|
||||
.RunResultAsync(conn)
|
||||
|> ignore
|
||||
|
||||
/// Update a post
|
||||
let updatePost conn post =
|
||||
r.Table(Table.Post)
|
||||
.Get(post.Id)
|
||||
.Replace( { post with Categories = []
|
||||
Comments = [] } )
|
||||
.RunResultAsync(conn)
|
||||
|> ignore
|
||||
|
||||
/// Save a post
|
||||
let savePost conn post =
|
||||
match post.Id with
|
47
src/MyWebLog.Data.RethinkDB/RethinkMyWebLogData.fs
Normal file
47
src/MyWebLog.Data.RethinkDB/RethinkMyWebLogData.fs
Normal file
|
@ -0,0 +1,47 @@
|
|||
namespace MyWebLog.Data.RethinkDB
|
||||
|
||||
open MyWebLog.Data
|
||||
open RethinkDb.Driver.Net
|
||||
|
||||
/// RethinkDB implementation of myWebLog data persistence
|
||||
type RethinkMyWebLogData(conn : IConnection, cfg : DataConfig) =
|
||||
interface IMyWebLogData with
|
||||
member this.SetUp = fun () -> SetUp.startUpCheck cfg
|
||||
|
||||
member this.AllCategories = Category.getAllCategories conn
|
||||
member this.CategoryById = Category.tryFindCategory conn
|
||||
member this.CategoryBySlug = Category.tryFindCategoryBySlug conn
|
||||
member this.AddCategory = Category.addCategory conn
|
||||
member this.UpdateCategory = Category.updateCategory conn
|
||||
member this.UpdateChildren = Category.updateChildren conn
|
||||
member this.DeleteCategory = Category.deleteCategory conn
|
||||
|
||||
member this.PageById = Page.tryFindPageById conn
|
||||
member this.PageByPermalink = Page.tryFindPageByPermalink conn
|
||||
member this.AllPages = Page.findAllPages conn
|
||||
member this.AddPage = Page.addPage conn
|
||||
member this.UpdatePage = Page.updatePage conn
|
||||
member this.DeletePage = Page.deletePage conn
|
||||
|
||||
member this.PageOfPublishedPosts = Post.findPageOfPublishedPosts conn
|
||||
member this.PageOfCategorizedPosts = Post.findPageOfCategorizedPosts conn
|
||||
member this.PageOfTaggedPosts = Post.findPageOfTaggedPosts conn
|
||||
member this.NewerPost = Post.tryFindNewerPost conn
|
||||
member this.NewerCategorizedPost = Post.tryFindNewerCategorizedPost conn
|
||||
member this.NewerTaggedPost = Post.tryFindNewerTaggedPost conn
|
||||
member this.OlderPost = Post.tryFindOlderPost conn
|
||||
member this.OlderCategorizedPost = Post.tryFindOlderCategorizedPost conn
|
||||
member this.OlderTaggedPost = Post.tryFindOlderTaggedPost conn
|
||||
member this.PageOfAllPosts = Post.findPageOfAllPosts conn
|
||||
member this.PostById = Post.tryFindPost conn
|
||||
member this.PostByPermalink = Post.tryFindPostByPermalink conn
|
||||
member this.PostByPriorPermalink = Post.tryFindPostByPriorPermalink conn
|
||||
member this.FeedPosts = Post.findFeedPosts conn
|
||||
member this.AddPost = Post.addPost conn
|
||||
member this.UpdatePost = Post.updatePost conn
|
||||
|
||||
member this.LogOn = User.tryUserLogOn conn
|
||||
|
||||
member this.WebLogByUrlBase = WebLog.tryFindWebLogByUrlBase conn
|
||||
member this.DashboardCounts = WebLog.findDashboardCounts conn
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
module MyWebLog.Data.SetUp
|
||||
module MyWebLog.Data.RethinkDB.SetUp
|
||||
|
||||
open Rethink
|
||||
open RethinkDb.Driver.Ast
|
||||
open System
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
/// Constants for tables used in myWebLog
|
||||
[<RequireQualifiedAccess>]
|
||||
module MyWebLog.Data.Table
|
||||
module MyWebLog.Data.RethinkDB.Table
|
||||
|
||||
/// The Category table
|
||||
let Category = "Category"
|
|
@ -1,7 +1,6 @@
|
|||
module MyWebLog.Data.User
|
||||
module MyWebLog.Data.RethinkDB.User
|
||||
|
||||
open MyWebLog.Entities
|
||||
open Rethink
|
||||
|
||||
let private r = RethinkDb.Driver.RethinkDB.R
|
||||
|
|
@ -1,20 +1,10 @@
|
|||
module MyWebLog.Data.WebLog
|
||||
module MyWebLog.Data.RethinkDB.WebLog
|
||||
|
||||
open MyWebLog.Entities
|
||||
open Rethink
|
||||
open RethinkDb.Driver.Ast
|
||||
|
||||
let private r = RethinkDb.Driver.RethinkDB.R
|
||||
|
||||
/// Counts of items displayed on the admin dashboard
|
||||
type DashboardCounts =
|
||||
{ /// The number of pages for the web log
|
||||
Pages : int
|
||||
/// The number of pages for the web log
|
||||
Posts : int
|
||||
/// The number of categories for the web log
|
||||
Categories : int }
|
||||
|
||||
/// Detemine the web log by the URL base
|
||||
let tryFindWebLogByUrlBase conn (urlBase : string) =
|
||||
r.Table(Table.WebLog)
|
2
src/MyWebLog.Data.RethinkDB/paket.references
Normal file
2
src/MyWebLog.Data.RethinkDB/paket.references
Normal file
|
@ -0,0 +1,2 @@
|
|||
FSharp.Interop.Dynamic
|
||||
RethinkDb.Driver
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
open Newtonsoft.Json
|
||||
|
||||
// ---- Constants ----
|
||||
// --- Constants ---
|
||||
|
||||
/// Constants to use for revision source language
|
||||
[<RequireQualifiedAccess>]
|
||||
|
@ -38,7 +38,7 @@ module CommentStatus =
|
|||
[<Literal>]
|
||||
let Spam = "Spam"
|
||||
|
||||
// ---- Entities ----
|
||||
// --- Entities ---
|
||||
|
||||
/// A revision of a post or page
|
||||
type Revision =
|
||||
|
@ -288,3 +288,14 @@ with
|
|||
Revisions = []
|
||||
Categories = []
|
||||
Comments = [] }
|
||||
|
||||
// --- UI Support ---
|
||||
|
||||
/// Counts of items displayed on the admin dashboard
|
||||
type DashboardCounts =
|
||||
{ /// The number of pages for the web log
|
||||
Pages : int
|
||||
/// The number of pages for the web log
|
||||
Posts : int
|
||||
/// The number of categories for the web log
|
||||
Categories : int }
|
114
src/MyWebLog.Entities/IMyWebLogData.fs
Normal file
114
src/MyWebLog.Entities/IMyWebLogData.fs
Normal file
|
@ -0,0 +1,114 @@
|
|||
namespace MyWebLog.Data
|
||||
|
||||
open MyWebLog.Entities
|
||||
|
||||
/// Interface required to provide data to myWebLog's logic layer
|
||||
type IMyWebLogData =
|
||||
/// Function to set up the data store
|
||||
abstract SetUp : (unit -> unit)
|
||||
|
||||
// --- Category ---
|
||||
|
||||
/// Get all categories for a web log
|
||||
abstract AllCategories : (string -> Category list)
|
||||
|
||||
/// Try to find a category by its Id and web log Id (web log, category Ids)
|
||||
abstract CategoryById : (string -> string -> Category option)
|
||||
|
||||
/// Try to find a category by its slug (web log Id, slug)
|
||||
abstract CategoryBySlug : (string -> string -> Category option)
|
||||
|
||||
/// Add a category
|
||||
abstract AddCategory : (Category -> unit)
|
||||
|
||||
/// Update a category
|
||||
abstract UpdateCategory : (Category -> unit)
|
||||
|
||||
/// Update a category's children
|
||||
abstract UpdateChildren : (string -> string -> string list -> unit)
|
||||
|
||||
/// Delete a Category
|
||||
abstract DeleteCategory : (Category -> unit)
|
||||
|
||||
// --- Page ---
|
||||
|
||||
/// Try to find a page by its Id and web log Id (web log, page Ids), choosing whether to include revisions
|
||||
abstract PageById : (string -> string -> bool -> Page option)
|
||||
|
||||
/// Try to find a page by its permalink and web log Id (web log Id, permalink)
|
||||
abstract PageByPermalink : (string -> string -> Page option)
|
||||
|
||||
/// Get all pages for a web log
|
||||
abstract AllPages : (string -> Page list)
|
||||
|
||||
/// Add a page
|
||||
abstract AddPage : (Page -> unit)
|
||||
|
||||
/// Update a page
|
||||
abstract UpdatePage : (Page -> unit)
|
||||
|
||||
/// Delete a page by its Id and web log Id (web log, page Ids)
|
||||
abstract DeletePage : (string -> string -> unit)
|
||||
|
||||
// --- Post ---
|
||||
|
||||
/// Find a page of published posts for the given web log (web log Id, page #, # per page)
|
||||
abstract PageOfPublishedPosts : (string -> int -> int -> Post list)
|
||||
|
||||
/// Find a page of published posts within a given category (web log Id, cat Id, page #, # per page)
|
||||
abstract PageOfCategorizedPosts : (string -> string -> int -> int -> Post list)
|
||||
|
||||
/// Find a page of published posts tagged with a given tag (web log Id, tag, page #, # per page)
|
||||
abstract PageOfTaggedPosts : (string -> string -> int -> int -> Post list)
|
||||
|
||||
/// Try to find the next newer published post for the given post
|
||||
abstract NewerPost : (Post -> Post option)
|
||||
|
||||
/// Try to find the next newer published post within a given category
|
||||
abstract NewerCategorizedPost : (string -> Post -> Post option)
|
||||
|
||||
/// Try to find the next newer published post tagged with a given tag
|
||||
abstract NewerTaggedPost : (string -> Post -> Post option)
|
||||
|
||||
/// Try to find the next older published post for the given post
|
||||
abstract OlderPost : (Post -> Post option)
|
||||
|
||||
/// Try to find the next older published post within a given category
|
||||
abstract OlderCategorizedPost : (string -> Post -> Post option)
|
||||
|
||||
/// Try to find the next older published post tagged with a given tag
|
||||
abstract OlderTaggedPost : (string -> Post -> Post option)
|
||||
|
||||
/// Find a page of all posts for the given web log (web log Id, page #, # per page)
|
||||
abstract PageOfAllPosts : (string -> int -> int -> Post list)
|
||||
|
||||
/// Try to find a post by its Id and web log Id (web log, post Ids)
|
||||
abstract PostById : (string -> string -> Post option)
|
||||
|
||||
/// Try to find a post by its permalink (web log Id, permalink)
|
||||
abstract PostByPermalink : (string -> string -> Post option)
|
||||
|
||||
/// Try to find a post by a prior permalink (web log Id, permalink)
|
||||
abstract PostByPriorPermalink : (string -> string -> Post option)
|
||||
|
||||
/// Get posts for the RSS feed for the given web log and number of posts
|
||||
abstract FeedPosts : (string -> int -> (Post * User option) list)
|
||||
|
||||
/// Add a post
|
||||
abstract AddPost : (Post -> unit)
|
||||
|
||||
/// Update a post
|
||||
abstract UpdatePost : (Post -> unit)
|
||||
|
||||
// --- User ---
|
||||
|
||||
/// Attempt to log on a user
|
||||
abstract LogOn : (string -> string -> User option)
|
||||
|
||||
// --- WebLog ---
|
||||
|
||||
/// Get a web log by its URL base
|
||||
abstract WebLogByUrlBase : (string -> WebLog option)
|
||||
|
||||
/// Get dashboard counts for a web log
|
||||
abstract DashboardCounts : (string -> DashboardCounts)
|
91
src/MyWebLog.Entities/MyWebLog.Entities.fsproj
Normal file
91
src/MyWebLog.Entities/MyWebLog.Entities.fsproj
Normal file
|
@ -0,0 +1,91 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>a87f3cf5-2189-442b-8acf-929f5153ac22</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>MyWebLog.Entities</RootNamespace>
|
||||
<AssemblyName>MyWebLog.Entities</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<TargetFSharpCoreVersion>4.4.0.0</TargetFSharpCoreVersion>
|
||||
<Name>MyWebLog.Entities</Name>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<Tailcalls>false</Tailcalls>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<WarningLevel>3</WarningLevel>
|
||||
<DocumentationFile>bin\Debug\MyWebLog.Entities.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<Tailcalls>true</Tailcalls>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<WarningLevel>3</WarningLevel>
|
||||
<DocumentationFile>bin\Release\MyWebLog.Entities.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="mscorlib" />
|
||||
<Reference Include="FSharp.Core, Version=$(TargetFSharpCoreVersion), Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Numerics" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Entities.fs" />
|
||||
<Compile Include="IMyWebLogData.fs" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<MinimumVisualStudioVersion Condition="'$(MinimumVisualStudioVersion)' == ''">11</MinimumVisualStudioVersion>
|
||||
</PropertyGroup>
|
||||
<Choose>
|
||||
<When Condition="'$(VisualStudioVersion)' == '11.0'">
|
||||
<PropertyGroup Condition="Exists('$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets')">
|
||||
<FSharpTargetsPath>$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets</FSharpTargetsPath>
|
||||
</PropertyGroup>
|
||||
</When>
|
||||
<Otherwise>
|
||||
<PropertyGroup Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets')">
|
||||
<FSharpTargetsPath>$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets</FSharpTargetsPath>
|
||||
</PropertyGroup>
|
||||
</Otherwise>
|
||||
</Choose>
|
||||
<Import Project="$(FSharpTargetsPath)" Condition="Exists('$(FSharpTargetsPath)')" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
<Choose>
|
||||
<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And $(TargetFrameworkVersion) == 'v4.0'">
|
||||
<ItemGroup>
|
||||
<Reference Include="Newtonsoft.Json">
|
||||
<HintPath>..\packages\Newtonsoft.Json\lib\net40\Newtonsoft.Json.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Paket>True</Paket>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</When>
|
||||
<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And ($(TargetFrameworkVersion) == 'v4.5' Or $(TargetFrameworkVersion) == 'v4.5.2')">
|
||||
<ItemGroup>
|
||||
<Reference Include="Newtonsoft.Json">
|
||||
<HintPath>..\packages\Newtonsoft.Json\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Paket>True</Paket>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</When>
|
||||
</Choose>
|
||||
</Project>
|
1
src/MyWebLog.Entities/paket.references
Normal file
1
src/MyWebLog.Entities/paket.references
Normal file
|
@ -0,0 +1 @@
|
|||
Newtonsoft.Json
|
56
src/MyWebLog.Logic/Category.fs
Normal file
56
src/MyWebLog.Logic/Category.fs
Normal file
|
@ -0,0 +1,56 @@
|
|||
module MyWebLog.Logic.Category
|
||||
|
||||
open MyWebLog.Data
|
||||
open MyWebLog.Entities
|
||||
|
||||
/// Sort categories by their name, with their children sorted below them, including an indent level
|
||||
let sortCategories categories =
|
||||
let rec getChildren (cat : Category) indent =
|
||||
seq {
|
||||
yield cat, indent
|
||||
for child in categories |> List.filter (fun c -> c.ParentId = Some cat.Id) do
|
||||
yield! getChildren child (indent + 1)
|
||||
}
|
||||
categories
|
||||
|> List.filter (fun c -> c.ParentId.IsNone)
|
||||
|> List.map (fun c -> getChildren c 0)
|
||||
|> Seq.collect id
|
||||
|> Seq.toList
|
||||
|
||||
/// Find all categories for a given web log
|
||||
let findAllCategories (data : IMyWebLogData) webLogId =
|
||||
data.AllCategories webLogId
|
||||
|> sortCategories
|
||||
|
||||
/// Try to find a category for a given web log Id and category Id
|
||||
let tryFindCategory (data : IMyWebLogData) webLogId catId = data.CategoryById webLogId catId
|
||||
|
||||
/// Try to find a category by its slug for a given web log
|
||||
let tryFindCategoryBySlug (data : IMyWebLogData) webLogId slug = data.CategoryBySlug webLogId slug
|
||||
|
||||
/// Save a category
|
||||
let saveCategory (data : IMyWebLogData) (cat : Category) =
|
||||
match cat.Id with
|
||||
| "new" -> let newCat = { cat with Id = string <| System.Guid.NewGuid() }
|
||||
data.AddCategory newCat
|
||||
newCat.Id
|
||||
| _ -> data.UpdateCategory cat
|
||||
cat.Id
|
||||
|
||||
/// Remove a category from its parent
|
||||
let removeCategoryFromParent (data : IMyWebLogData) webLogId parentId catId =
|
||||
match tryFindCategory data webLogId parentId with
|
||||
| Some parent -> parent.Children
|
||||
|> List.filter (fun childId -> childId <> catId)
|
||||
|> data.UpdateChildren webLogId parentId
|
||||
| None -> ()
|
||||
|
||||
/// Add a category to a given parent
|
||||
let addCategoryToParent (data : IMyWebLogData) webLogId parentId catId =
|
||||
match tryFindCategory data webLogId parentId with
|
||||
| Some parent -> catId :: parent.Children
|
||||
|> data.UpdateChildren webLogId parentId
|
||||
| None -> ()
|
||||
|
||||
/// Delete a category
|
||||
let deleteCategory (data : IMyWebLogData) cat = data.DeleteCategory cat
|
|
@ -1,18 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>1fba0b84-b09e-4b16-b9b6-5730dea27192</ProjectGuid>
|
||||
<ProjectGuid>29f6eda3-4f43-4bb3-9c63-ae238a9b7f12</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>myWebLog.Data</RootNamespace>
|
||||
<AssemblyName>MyWebLog.Data</AssemblyName>
|
||||
<RootNamespace>MyWebLog.Logic</RootNamespace>
|
||||
<AssemblyName>MyWebLog.Logic</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<TargetFSharpCoreVersion>4.4.0.0</TargetFSharpCoreVersion>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<Name>myWebLog.Data</Name>
|
||||
<Name>MyWebLog.Logic</Name>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
|
@ -22,7 +21,7 @@
|
|||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<WarningLevel>3</WarningLevel>
|
||||
<DocumentationFile>bin\Debug\MyWebLog.Data.xml</DocumentationFile>
|
||||
<DocumentationFile>bin\Debug\MyWebLog.Logic.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
|
@ -31,8 +30,31 @@
|
|||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<WarningLevel>3</WarningLevel>
|
||||
<DocumentationFile>bin\Release\myWebLog.Data.XML</DocumentationFile>
|
||||
<DocumentationFile>bin\Release\MyWebLog.Logic.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="mscorlib" />
|
||||
<Reference Include="FSharp.Core, Version=$(TargetFSharpCoreVersion), Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Numerics" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Category.fs" />
|
||||
<Compile Include="Page.fs" />
|
||||
<Compile Include="Post.fs" />
|
||||
<Compile Include="User.fs" />
|
||||
<Compile Include="WebLog.fs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MyWebLog.Entities\MyWebLog.Entities.fsproj">
|
||||
<Name>MyWebLog.Entities</Name>
|
||||
<Project>{a87f3cf5-2189-442b-8acf-929f5153ac22}</Project>
|
||||
<Private>True</Private>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<MinimumVisualStudioVersion Condition="'$(MinimumVisualStudioVersion)' == ''">11</MinimumVisualStudioVersion>
|
||||
</PropertyGroup>
|
||||
|
@ -48,61 +70,12 @@
|
|||
</PropertyGroup>
|
||||
</Otherwise>
|
||||
</Choose>
|
||||
<Import Project="$(FSharpTargetsPath)" />
|
||||
<ItemGroup>
|
||||
<Compile Include="AssemblyInfo.fs" />
|
||||
<Compile Include="Entities.fs" />
|
||||
<Compile Include="Table.fs" />
|
||||
<Compile Include="DataConfig.fs" />
|
||||
<Compile Include="Rethink.fs" />
|
||||
<Compile Include="SetUp.fs" />
|
||||
<Compile Include="Category.fs" />
|
||||
<Compile Include="Page.fs" />
|
||||
<Compile Include="Post.fs" />
|
||||
<Compile Include="User.fs" />
|
||||
<Compile Include="WebLog.fs" />
|
||||
<None Include="ConvertOld.fsx" />
|
||||
<Content Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Common.Logging">
|
||||
<HintPath>..\packages\Common.Logging.3.3.1\lib\net40\Common.Logging.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Common.Logging.Core">
|
||||
<HintPath>..\packages\Common.Logging.Core.3.3.1\lib\net40\Common.Logging.Core.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Dynamitey">
|
||||
<HintPath>..\packages\Dynamitey.1.0.2.0\lib\net40\Dynamitey.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="FSharp.Core">
|
||||
<HintPath>..\packages\FSharp.Core.4.0.0.1\lib\net40\FSharp.Core.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="FSharp.Interop.Dynamic">
|
||||
<HintPath>..\packages\FSharp.Interop.Dynamic.3.0.0.0\lib\portable-net45+sl50+win\FSharp.Interop.Dynamic.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="mscorlib" />
|
||||
<Reference Include="Newtonsoft.Json">
|
||||
<HintPath>..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="RethinkDb.Driver">
|
||||
<HintPath>..\packages\RethinkDb.Driver.2.3.9\lib\net45\RethinkDb.Driver.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Numerics" />
|
||||
</ItemGroup>
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
<Import Project="$(FSharpTargetsPath)" Condition="Exists('$(FSharpTargetsPath)')" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
29
src/MyWebLog.Logic/Page.fs
Normal file
29
src/MyWebLog.Logic/Page.fs
Normal file
|
@ -0,0 +1,29 @@
|
|||
/// Logic for manipulating <see cref="Page" /> entities
|
||||
module MyWebLog.Logic.Page
|
||||
|
||||
open MyWebLog.Data
|
||||
open MyWebLog.Entities
|
||||
|
||||
/// Find a page by its Id and web log Id
|
||||
let tryFindPage (data : IMyWebLogData) webLogId pageId = data.PageById webLogId pageId true
|
||||
|
||||
/// Find a page by its Id and web log Id, without the revision list
|
||||
let tryFindPageWithoutRevisions (data : IMyWebLogData) webLogId pageId = data.PageById webLogId pageId false
|
||||
|
||||
/// Find a page by its permalink
|
||||
let tryFindPageByPermalink (data : IMyWebLogData) webLogId permalink = data.PageByPermalink webLogId permalink
|
||||
|
||||
/// Find a list of all pages (excludes text and revisions)
|
||||
let findAllPages (data : IMyWebLogData) webLogId = data.AllPages webLogId
|
||||
|
||||
/// Save a page
|
||||
let savePage (data : IMyWebLogData) (page : Page) =
|
||||
match page.Id with
|
||||
| "new" -> let newPg = { page with Id = string <| System.Guid.NewGuid() }
|
||||
data.AddPage newPg
|
||||
newPg.Id
|
||||
| _ -> data.UpdatePage page
|
||||
page.Id
|
||||
|
||||
/// Delete a page
|
||||
let deletePage (data : IMyWebLogData) webLogId pageId = data.DeletePage webLogId pageId
|
60
src/MyWebLog.Logic/Post.fs
Normal file
60
src/MyWebLog.Logic/Post.fs
Normal file
|
@ -0,0 +1,60 @@
|
|||
/// Logic for manipulating <see cref="Post" /> entities
|
||||
module MyWebLog.Logic.Post
|
||||
|
||||
open MyWebLog.Data
|
||||
open MyWebLog.Entities
|
||||
|
||||
/// Find a page of published posts
|
||||
let findPageOfPublishedPosts (data : IMyWebLogData) webLogId pageNbr nbrPerPage =
|
||||
data.PageOfPublishedPosts webLogId pageNbr nbrPerPage
|
||||
|
||||
/// Find a pages of published posts in a given category
|
||||
let findPageOfCategorizedPosts (data : IMyWebLogData) webLogId catId pageNbr nbrPerPage =
|
||||
data.PageOfCategorizedPosts webLogId catId pageNbr nbrPerPage
|
||||
|
||||
/// Find a page of published posts tagged with a given tag
|
||||
let findPageOfTaggedPosts (data : IMyWebLogData) webLogId tag pageNbr nbrPerPage =
|
||||
data.PageOfTaggedPosts webLogId tag pageNbr nbrPerPage
|
||||
|
||||
/// Find the next newer published post for the given post
|
||||
let tryFindNewerPost (data : IMyWebLogData) post = data.NewerPost post
|
||||
|
||||
/// Find the next newer published post in a given category for the given post
|
||||
let tryFindNewerCategorizedPost (data : IMyWebLogData) catId post = data.NewerCategorizedPost catId post
|
||||
|
||||
/// Find the next newer published post tagged with a given tag for the given post
|
||||
let tryFindNewerTaggedPost (data : IMyWebLogData) tag post = data.NewerTaggedPost tag post
|
||||
|
||||
/// Find the next older published post for the given post
|
||||
let tryFindOlderPost (data : IMyWebLogData) post = data.OlderPost post
|
||||
|
||||
/// Find the next older published post in a given category for the given post
|
||||
let tryFindOlderCategorizedPost (data : IMyWebLogData) catId post = data.OlderCategorizedPost catId post
|
||||
|
||||
/// Find the next older published post tagged with a given tag for the given post
|
||||
let tryFindOlderTaggedPost (data : IMyWebLogData) tag post = data.OlderTaggedPost tag post
|
||||
|
||||
/// Find a page of all posts for a web log
|
||||
let findPageOfAllPosts (data : IMyWebLogData) webLogId pageNbr nbrPerPage =
|
||||
data.PageOfAllPosts webLogId pageNbr nbrPerPage
|
||||
|
||||
/// Try to find a post by its Id
|
||||
let tryFindPost (data : IMyWebLogData) webLogId postId = data.PostById webLogId postId
|
||||
|
||||
/// Try to find a post by its permalink
|
||||
let tryFindPostByPermalink (data : IMyWebLogData) webLogId permalink = data.PostByPermalink webLogId permalink
|
||||
|
||||
/// Try to find a post by its prior permalink
|
||||
let tryFindPostByPriorPermalink (data : IMyWebLogData) webLogId permalink = data.PostByPriorPermalink webLogId permalink
|
||||
|
||||
/// Find posts for the RSS feed
|
||||
let findFeedPosts (data : IMyWebLogData) webLogId nbrOfPosts = data.FeedPosts webLogId nbrOfPosts
|
||||
|
||||
/// Save a post
|
||||
let savePost (data : IMyWebLogData) post =
|
||||
match post.Id with
|
||||
| "new" -> let newPost = { post with Id = string <| System.Guid.NewGuid() }
|
||||
data.AddPost newPost
|
||||
newPost.Id
|
||||
| _ -> data.UpdatePost post
|
||||
post.Id
|
7
src/MyWebLog.Logic/User.fs
Normal file
7
src/MyWebLog.Logic/User.fs
Normal file
|
@ -0,0 +1,7 @@
|
|||
/// Logic for manipulating <see cref="User" /> entities
|
||||
module MyWebLog.Logic.User
|
||||
|
||||
open MyWebLog.Data
|
||||
|
||||
/// Try to log on a user
|
||||
let tryUserLogOn (data : IMyWebLogData) email passwordHash = data.LogOn email passwordHash
|
11
src/MyWebLog.Logic/WebLog.fs
Normal file
11
src/MyWebLog.Logic/WebLog.fs
Normal file
|
@ -0,0 +1,11 @@
|
|||
/// Logic for manipulating <see cref="WebLog" /> entities
|
||||
module MyWebLog.Logic.WebLog
|
||||
|
||||
open MyWebLog.Data
|
||||
open MyWebLog.Entities
|
||||
|
||||
/// Find a web log by its URL base
|
||||
let tryFindWebLogByUrlBase (data : IMyWebLogData) urlBase = data.WebLogByUrlBase urlBase
|
||||
|
||||
/// Find the counts for the admin dashboard
|
||||
let findDashboardCounts (data : IMyWebLogData) webLogId = data.DashboardCounts webLogId
|
4
src/MyWebLog.Tests/MyWebLog.Tests.fs
Normal file
4
src/MyWebLog.Tests/MyWebLog.Tests.fs
Normal file
|
@ -0,0 +1,4 @@
|
|||
namespace MyWebLog.Web
|
||||
|
||||
type Web() =
|
||||
member this.X = "F#"
|
70
src/MyWebLog.Tests/MyWebLog.Tests.fsproj
Normal file
70
src/MyWebLog.Tests/MyWebLog.Tests.fsproj
Normal file
|
@ -0,0 +1,70 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>07e60874-6cf5-4d53-aee0-f17ef28228dd</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>MyWebLog.Tests</RootNamespace>
|
||||
<AssemblyName>MyWebLog.Tests</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<TargetFSharpCoreVersion>4.4.0.0</TargetFSharpCoreVersion>
|
||||
<Name>MyWebLog.Tests</Name>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<Tailcalls>false</Tailcalls>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<WarningLevel>3</WarningLevel>
|
||||
<DocumentationFile>bin\Debug\MyWebLog.Tests.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<Tailcalls>true</Tailcalls>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<WarningLevel>3</WarningLevel>
|
||||
<DocumentationFile>bin\Release\MyWebLog.Tests.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="mscorlib" />
|
||||
<Reference Include="FSharp.Core, Version=$(TargetFSharpCoreVersion), Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Numerics" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="MyWebLog.Tests.fs" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<MinimumVisualStudioVersion Condition="'$(MinimumVisualStudioVersion)' == ''">11</MinimumVisualStudioVersion>
|
||||
</PropertyGroup>
|
||||
<Choose>
|
||||
<When Condition="'$(VisualStudioVersion)' == '11.0'">
|
||||
<PropertyGroup Condition="Exists('$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets')">
|
||||
<FSharpTargetsPath>$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets</FSharpTargetsPath>
|
||||
</PropertyGroup>
|
||||
</When>
|
||||
<Otherwise>
|
||||
<PropertyGroup Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets')">
|
||||
<FSharpTargetsPath>$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets</FSharpTargetsPath>
|
||||
</PropertyGroup>
|
||||
</Otherwise>
|
||||
</Choose>
|
||||
<Import Project="$(FSharpTargetsPath)" Condition="Exists('$(FSharpTargetsPath)')" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
14
src/build.cmd
Normal file
14
src/build.cmd
Normal file
|
@ -0,0 +1,14 @@
|
|||
@echo off
|
||||
cls
|
||||
|
||||
.paket\paket.bootstrapper.exe
|
||||
if errorlevel 1 (
|
||||
exit /b %errorlevel%
|
||||
)
|
||||
|
||||
.paket\paket.exe restore
|
||||
if errorlevel 1 (
|
||||
exit /b %errorlevel%
|
||||
)
|
||||
|
||||
packages\FAKE\tools\FAKE.exe build.fsx %*
|
42
src/build.fsx
Normal file
42
src/build.fsx
Normal file
|
@ -0,0 +1,42 @@
|
|||
// include Fake libs
|
||||
#r "./packages/FAKE/tools/FakeLib.dll"
|
||||
|
||||
open Fake
|
||||
|
||||
// Directories
|
||||
let buildDir = "./build/"
|
||||
let deployDir = "./deploy/"
|
||||
|
||||
|
||||
// Filesets
|
||||
let appReferences =
|
||||
!! "/**/*.csproj"
|
||||
++ "/**/*.fsproj"
|
||||
|
||||
// version info
|
||||
let version = "0.1" // or retrieve from CI server
|
||||
|
||||
// Targets
|
||||
Target "Clean" (fun _ ->
|
||||
CleanDirs [buildDir; deployDir]
|
||||
)
|
||||
|
||||
Target "Build" (fun _ ->
|
||||
// compile all projects below src/app/
|
||||
MSBuildDebug buildDir "Build" appReferences
|
||||
|> Log "AppBuild-Output: "
|
||||
)
|
||||
|
||||
Target "Deploy" (fun _ ->
|
||||
!! (buildDir + "/**/*.*")
|
||||
-- "*.zip"
|
||||
|> Zip buildDir (deployDir + "ApplicationName." + version + ".zip")
|
||||
)
|
||||
|
||||
// Build order
|
||||
"Clean"
|
||||
==> "Build"
|
||||
==> "Deploy"
|
||||
|
||||
// start build
|
||||
RunTargetOrDefault "Build"
|
33
src/build.sh
Normal file
33
src/build.sh
Normal file
|
@ -0,0 +1,33 @@
|
|||
#!/bin/bash
|
||||
if test "$OS" = "Windows_NT"
|
||||
then
|
||||
# use .Net
|
||||
|
||||
.paket/paket.bootstrapper.exe
|
||||
exit_code=$?
|
||||
if [ $exit_code -ne 0 ]; then
|
||||
exit $exit_code
|
||||
fi
|
||||
|
||||
.paket/paket.exe restore
|
||||
exit_code=$?
|
||||
if [ $exit_code -ne 0 ]; then
|
||||
exit $exit_code
|
||||
fi
|
||||
|
||||
packages/FAKE/tools/FAKE.exe $@ --fsiargs build.fsx
|
||||
else
|
||||
# use mono
|
||||
mono .paket/paket.bootstrapper.exe
|
||||
exit_code=$?
|
||||
if [ $exit_code -ne 0 ]; then
|
||||
exit $exit_code
|
||||
fi
|
||||
|
||||
mono .paket/paket.exe restore
|
||||
exit_code=$?
|
||||
if [ $exit_code -ne 0 ]; then
|
||||
exit $exit_code
|
||||
fi
|
||||
mono packages/FAKE/tools/FAKE.exe $@ --fsiargs -d:MONO build.fsx
|
||||
fi
|
|
@ -1,77 +0,0 @@
|
|||
module MyWebLog.Data.Page
|
||||
|
||||
open FSharp.Interop.Dynamic
|
||||
open MyWebLog.Entities
|
||||
open Rethink
|
||||
open RethinkDb.Driver.Ast
|
||||
open System.Dynamic
|
||||
|
||||
let private r = RethinkDb.Driver.RethinkDB.R
|
||||
|
||||
/// Shorthand to get the page by its Id, filtering on web log Id
|
||||
let private page (webLogId : string) (pageId : string) =
|
||||
r.Table(Table.Page)
|
||||
.Get(pageId)
|
||||
.Filter(ReqlFunction1(fun p -> upcast p.["WebLogId"].Eq(webLogId)))
|
||||
|
||||
/// Get a page by its Id
|
||||
let tryFindPage conn webLogId pageId =
|
||||
match r.Table(Table.Page)
|
||||
.Get(pageId)
|
||||
.RunAtomAsync<Page>(conn) |> await |> box with
|
||||
| null -> None
|
||||
| page -> let pg : Page = unbox page
|
||||
match pg.WebLogId = webLogId with true -> Some pg | _ -> None
|
||||
|
||||
/// Get a page by its Id (excluding revisions)
|
||||
let tryFindPageWithoutRevisions conn webLogId pageId : Page option =
|
||||
match (page webLogId pageId)
|
||||
.Without("Revisions")
|
||||
.RunAtomAsync<Page>(conn) |> await |> box with
|
||||
| null -> None
|
||||
| page -> Some <| unbox page
|
||||
|
||||
/// Find a page by its permalink
|
||||
let tryFindPageByPermalink conn (webLogId : string) (permalink : string) =
|
||||
r.Table(Table.Page)
|
||||
.GetAll(r.Array(webLogId, permalink)).OptArg("index", "Permalink")
|
||||
.Without("Revisions")
|
||||
.RunCursorAsync<Page>(conn)
|
||||
|> await
|
||||
|> Seq.tryHead
|
||||
|
||||
/// Get a list of all pages (excludes page text and revisions)
|
||||
let findAllPages conn (webLogId : string) =
|
||||
r.Table(Table.Page)
|
||||
.GetAll(webLogId).OptArg("index", "WebLogId")
|
||||
.OrderBy("Title")
|
||||
.Without("Text", "Revisions")
|
||||
.RunListAsync<Page>(conn)
|
||||
|> await
|
||||
|> Seq.toList
|
||||
|
||||
/// Save a page
|
||||
let savePage conn (pg : Page) =
|
||||
match pg.Id with
|
||||
| "new" -> let newPage = { pg with Id = string <| System.Guid.NewGuid() }
|
||||
r.Table(Table.Page)
|
||||
.Insert(page)
|
||||
.RunResultAsync(conn) |> await |> ignore
|
||||
newPage.Id
|
||||
| _ -> let upd8 = ExpandoObject()
|
||||
upd8?Title <- pg.Title
|
||||
upd8?Permalink <- pg.Permalink
|
||||
upd8?PublishedOn <- pg.PublishedOn
|
||||
upd8?UpdatedOn <- pg.UpdatedOn
|
||||
upd8?Text <- pg.Text
|
||||
upd8?Revisions <- pg.Revisions
|
||||
(page pg.WebLogId pg.Id)
|
||||
.Update(upd8)
|
||||
.RunResultAsync(conn) |> await |> ignore
|
||||
pg.Id
|
||||
|
||||
/// Delete a page
|
||||
let deletePage conn webLogId pageId =
|
||||
(page webLogId pageId)
|
||||
.Delete()
|
||||
.RunResultAsync(conn) |> await |> ignore
|
|
@ -1,10 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Common.Logging" version="3.3.1" targetFramework="net452" />
|
||||
<package id="Common.Logging.Core" version="3.3.1" targetFramework="net452" />
|
||||
<package id="Dynamitey" version="1.0.2.0" targetFramework="net452" />
|
||||
<package id="FSharp.Core" version="4.0.0.1" targetFramework="net452" />
|
||||
<package id="FSharp.Interop.Dynamic" version="3.0.0.0" targetFramework="net452" />
|
||||
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net452" />
|
||||
<package id="RethinkDb.Driver" version="2.3.9" targetFramework="net452" />
|
||||
</packages>
|
|
@ -1,186 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>e6ee110a-27a6-4a19-b0cb-d24f48f71b53</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>myWebLog.Web</RootNamespace>
|
||||
<AssemblyName>MyWebLog.Web</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<TargetFSharpCoreVersion>4.4.0.0</TargetFSharpCoreVersion>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<Name>myWebLog.Web</Name>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<Tailcalls>false</Tailcalls>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<WarningLevel>3</WarningLevel>
|
||||
<DocumentationFile>bin\Debug\MyWebLog.Web.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<Tailcalls>true</Tailcalls>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<WarningLevel>3</WarningLevel>
|
||||
<DocumentationFile>bin\Release\myWebLog.Web.XML</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<MinimumVisualStudioVersion Condition="'$(MinimumVisualStudioVersion)' == ''">11</MinimumVisualStudioVersion>
|
||||
</PropertyGroup>
|
||||
<Choose>
|
||||
<When Condition="'$(VisualStudioVersion)' == '11.0'">
|
||||
<PropertyGroup Condition="Exists('$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets')">
|
||||
<FSharpTargetsPath>$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets</FSharpTargetsPath>
|
||||
</PropertyGroup>
|
||||
</When>
|
||||
<Otherwise>
|
||||
<PropertyGroup Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets')">
|
||||
<FSharpTargetsPath>$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets</FSharpTargetsPath>
|
||||
</PropertyGroup>
|
||||
</Otherwise>
|
||||
</Choose>
|
||||
<Import Project="$(FSharpTargetsPath)" />
|
||||
<ItemGroup>
|
||||
<Compile Include="AssemblyInfo.fs" />
|
||||
<Compile Include="Keys.fs" />
|
||||
<Compile Include="AppConfig.fs" />
|
||||
<Compile Include="ViewModels.fs" />
|
||||
<Compile Include="ModuleExtensions.fs" />
|
||||
<Compile Include="AdminModule.fs" />
|
||||
<Compile Include="CategoryModule.fs" />
|
||||
<Compile Include="PageModule.fs" />
|
||||
<Compile Include="PostModule.fs" />
|
||||
<Compile Include="UserModule.fs" />
|
||||
<Compile Include="App.fs" />
|
||||
<Content Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Common.Logging">
|
||||
<HintPath>..\packages\Common.Logging.3.3.1\lib\net40\Common.Logging.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Common.Logging.Core">
|
||||
<HintPath>..\packages\Common.Logging.Core.3.3.1\lib\net40\Common.Logging.Core.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="CSharpFormat">
|
||||
<HintPath>..\packages\FSharp.Formatting.2.14.4\lib\net40\CSharpFormat.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Dynamitey">
|
||||
<HintPath>..\packages\Dynamitey.1.0.2.0\lib\net40\Dynamitey.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="FSharp.CodeFormat">
|
||||
<HintPath>..\packages\FSharp.Formatting.2.14.4\lib\net40\FSharp.CodeFormat.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="FSharp.Compiler.Service">
|
||||
<HintPath>..\packages\FSharp.Compiler.Service.2.0.0.6\lib\net45\FSharp.Compiler.Service.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="FSharp.Core">
|
||||
<HintPath>..\packages\FSharp.Core.4.0.0.1\lib\net40\FSharp.Core.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="FSharp.Formatting.Common">
|
||||
<HintPath>..\packages\FSharp.Formatting.2.14.4\lib\net40\FSharp.Formatting.Common.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="FSharp.Interop.Dynamic">
|
||||
<HintPath>..\packages\FSharp.Interop.Dynamic.3.0.0.0\lib\portable-net45+sl50+win\FSharp.Interop.Dynamic.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="FSharp.Literate">
|
||||
<HintPath>..\packages\FSharp.Formatting.2.14.4\lib\net40\FSharp.Literate.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="FSharp.Markdown">
|
||||
<HintPath>..\packages\FSharp.Formatting.2.14.4\lib\net40\FSharp.Markdown.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="FSharp.MetadataFormat">
|
||||
<HintPath>..\packages\FSharp.Formatting.2.14.4\lib\net40\FSharp.MetadataFormat.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="FSharpVSPowerTools.Core">
|
||||
<HintPath>..\packages\FSharpVSPowerTools.Core.2.3.0\lib\net45\FSharpVSPowerTools.Core.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="mscorlib" />
|
||||
<Reference Include="Nancy">
|
||||
<HintPath>..\packages\Nancy.1.4.3\lib\net40\Nancy.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Nancy.Authentication.Forms">
|
||||
<HintPath>..\packages\Nancy.Authentication.Forms.1.4.1\lib\net40\Nancy.Authentication.Forms.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Nancy.Session.Persistable">
|
||||
<HintPath>..\packages\Nancy.Session.Persistable.0.9.0\lib\net452\Nancy.Session.Persistable.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Nancy.Session.RethinkDb">
|
||||
<HintPath>..\packages\Nancy.Session.RethinkDB.0.9.0\lib\net452\Nancy.Session.RethinkDb.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json">
|
||||
<HintPath>..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="NodaTime">
|
||||
<HintPath>..\packages\NodaTime.1.3.2\lib\net35-Client\NodaTime.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="RazorEngine">
|
||||
<HintPath>..\packages\FSharp.Formatting.2.14.4\lib\net40\RazorEngine.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="RethinkDb.Driver">
|
||||
<HintPath>..\packages\RethinkDb.Driver.2.3.9\lib\net45\RethinkDb.Driver.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Suave">
|
||||
<HintPath>..\packages\Suave.1.1.3\lib\net40\Suave.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.ComponentModel.DataAnnotations" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Numerics" />
|
||||
<Reference Include="System.ServiceModel" />
|
||||
<Reference Include="System.Web.Razor">
|
||||
<HintPath>..\packages\FSharp.Formatting.2.14.4\lib\net40\System.Web.Razor.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\myWebLog.Data\myWebLog.Data.fsproj">
|
||||
<Name>myWebLog.Data</Name>
|
||||
<Project>{1fba0b84-b09e-4b16-b9b6-5730dea27192}</Project>
|
||||
<Private>True</Private>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\myWebLog.Resources\myWebLog.Resources.csproj">
|
||||
<Name>myWebLog.Resources</Name>
|
||||
<Project>{a12ea8da-88bc-4447-90cb-a0e2dcc37523}</Project>
|
||||
<Private>True</Private>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
|
@ -1,19 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Common.Logging" version="3.3.1" targetFramework="net452" />
|
||||
<package id="Common.Logging.Core" version="3.3.1" targetFramework="net452" />
|
||||
<package id="Dynamitey" version="1.0.2.0" targetFramework="net452" />
|
||||
<package id="FSharp.Compiler.Service" version="2.0.0.6" targetFramework="net452" />
|
||||
<package id="FSharp.Core" version="4.0.0.1" targetFramework="net452" />
|
||||
<package id="FSharp.Formatting" version="2.14.4" targetFramework="net452" />
|
||||
<package id="FSharp.Interop.Dynamic" version="3.0.0.0" targetFramework="net452" />
|
||||
<package id="FSharpVSPowerTools.Core" version="2.3.0" targetFramework="net452" />
|
||||
<package id="Nancy" version="1.4.3" targetFramework="net452" />
|
||||
<package id="Nancy.Authentication.Forms" version="1.4.1" targetFramework="net452" />
|
||||
<package id="Nancy.Session.Persistable" version="0.9.0" targetFramework="net452" />
|
||||
<package id="Nancy.Session.RethinkDB" version="0.9.0" targetFramework="net452" />
|
||||
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net452" />
|
||||
<package id="NodaTime" version="1.3.2" targetFramework="net452" />
|
||||
<package id="RethinkDb.Driver" version="2.3.9" targetFramework="net452" />
|
||||
<package id="Suave" version="1.1.3" targetFramework="net452" />
|
||||
</packages>
|
|
@ -1,39 +1,14 @@
|
|||
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.25420.1
|
||||
# Visual Studio 2013
|
||||
VisualStudioVersion = 12.0.31101.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "myWebLog", "myWebLog\myWebLog.csproj", "{B9F6DB52-65A1-4C2A-8C97-739E08A1D4FB}"
|
||||
EndProject
|
||||
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "myWebLog.Web", "myWebLog.Web\myWebLog.Web.fsproj", "{E6EE110A-27A6-4A19-B0CB-D24F48F71B53}"
|
||||
EndProject
|
||||
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "myWebLog.Data", "myWebLog.Data\myWebLog.Data.fsproj", "{1FBA0B84-B09E-4B16-B9B6-5730DEA27192}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "myWebLog.Resources", "myWebLog.Resources\myWebLog.Resources.csproj", "{A12EA8DA-88BC-4447-90CB-A0E2DCC37523}"
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".paket", ".paket", "{DF15419B-90C6-4F45-8EC1-7A63C5D3565C}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
paket.dependencies = paket.dependencies
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{B9F6DB52-65A1-4C2A-8C97-739E08A1D4FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B9F6DB52-65A1-4C2A-8C97-739E08A1D4FB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B9F6DB52-65A1-4C2A-8C97-739E08A1D4FB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B9F6DB52-65A1-4C2A-8C97-739E08A1D4FB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E6EE110A-27A6-4A19-B0CB-D24F48F71B53}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E6EE110A-27A6-4A19-B0CB-D24F48F71B53}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E6EE110A-27A6-4A19-B0CB-D24F48F71B53}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E6EE110A-27A6-4A19-B0CB-D24F48F71B53}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1FBA0B84-B09E-4B16-B9B6-5730DEA27192}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1FBA0B84-B09E-4B16-B9B6-5730DEA27192}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1FBA0B84-B09E-4B16-B9B6-5730DEA27192}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1FBA0B84-B09E-4B16-B9B6-5730DEA27192}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A12EA8DA-88BC-4447-90CB-A0E2DCC37523}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A12EA8DA-88BC-4447-90CB-A0E2DCC37523}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A12EA8DA-88BC-4447-90CB-A0E2DCC37523}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A12EA8DA-88BC-4447-90CB-A0E2DCC37523}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
|
|
|
@ -15,7 +15,20 @@
|
|||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
|
||||
<system.data>
|
||||
<DbProviderFactories>
|
||||
<add name="SqlClient Data Provider"
|
||||
invariant="System.Data.SqlClient"
|
||||
description=".NET Framework Data Provider for SQL Server"
|
||||
type="System.Data.SqlClient.SqlClientFactory, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
</DbProviderFactories>
|
||||
</system.data>
|
||||
<connectionStrings>
|
||||
<clear />
|
||||
<add name="SessionStore"
|
||||
providerName="System.Data.SqlClient"
|
||||
connectionString="Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=C:\Users\danie\Documents\Sandbox\myWebLog\src\myWebLog\session.mdf;Integrated Security=True;Connect Timeout=30" />
|
||||
</connectionStrings>
|
||||
</configuration>
|
||||
<!-- publicKeyToken="32ab4ba45e0a69a1"
|
||||
culture="neutral"
|
||||
|
|
|
@ -56,20 +56,27 @@
|
|||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\myWebLog.Data\myWebLog.Data.fsproj">
|
||||
<Project>{1fba0b84-b09e-4b16-b9b6-5730dea27192}</Project>
|
||||
<Name>myWebLog.Data</Name>
|
||||
<ProjectReference Include="..\MyWebLog.App\MyWebLog.App.fsproj">
|
||||
<Project>{9cea3a8b-e8aa-44e6-9f5f-2095ceed54eb}</Project>
|
||||
<Name>MyWebLog.App</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\myWebLog.Resources\myWebLog.Resources.csproj">
|
||||
<ProjectReference Include="..\MyWebLog.Data.RethinkDB\MyWebLog.Data.RethinkDB.fsproj">
|
||||
<Project>{d6c2be5e-883a-4f34-9905-b730543ca380}</Project>
|
||||
<Name>myWebLog.Web</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MyWebLog.Entities\MyWebLog.Entities.fsproj">
|
||||
<Project>{a87f3cf5-2189-442b-8acf-929f5153ac22}</Project>
|
||||
<Name>MyWebLog.Entities</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MyWebLog.Logic\MyWebLog.Logic.fsproj">
|
||||
<Project>{29f6eda3-4f43-4bb3-9c63-ae238a9b7f12}</Project>
|
||||
<Name>MyWebLog.Entities</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MyWebLog.Resources\MyWebLog.Resources.csproj">
|
||||
<Project>{a12ea8da-88bc-4447-90cb-a0e2dcc37523}</Project>
|
||||
<Name>myWebLog.Resources</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\myWebLog.Web\myWebLog.Web.fsproj">
|
||||
<Project>{e6ee110a-27a6-4a19-b0cb-d24f48f71b53}</Project>
|
||||
<Name>myWebLog.Web</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<ItemGroup>
|
||||
<Content Include="content\scripts\tinymce-init.js" />
|
||||
<Content Include="content\styles\admin.css" />
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<article>
|
||||
<h1>
|
||||
<a href="/@Current.Post.Permalink"
|
||||
title="@Translate.PermanentLinkTo "@Current.Post.Title@quot;">@Current.Post.Title</a>
|
||||
title="@Translate.PermanentLinkTo "@Current.Post.Title"">@Current.Post.Title</a>
|
||||
</h1>
|
||||
<p>
|
||||
<i class="fa fa-calendar" title="@Translate.Date"></i> @Current.PublishedDate
|
||||
|
|
13
src/paket.dependencies
Normal file
13
src/paket.dependencies
Normal file
|
@ -0,0 +1,13 @@
|
|||
framework: net40, net45, net452
|
||||
source https://www.nuget.org/api/v2
|
||||
nuget Common.Logging 3.3.0
|
||||
nuget FAKE
|
||||
nuget FSharp.Interop.Dynamic
|
||||
nuget FSharp.Formatting
|
||||
nuget Nancy
|
||||
nuget Nancy.Authentication.Forms
|
||||
nuget Nancy.Session.RethinkDb
|
||||
nuget Newtonsoft.Json
|
||||
nuget NodaTime
|
||||
nuget RethinkDb.Driver
|
||||
nuget Suave
|
34
src/paket.lock
Normal file
34
src/paket.lock
Normal file
|
@ -0,0 +1,34 @@
|
|||
FRAMEWORK: NET40, NET45, NET452
|
||||
NUGET
|
||||
remote: https://www.nuget.org/api/v2
|
||||
Common.Logging (3.3)
|
||||
Common.Logging.Core (>= 3.3)
|
||||
Common.Logging.Core (3.3.1)
|
||||
Dynamitey (1.0.2)
|
||||
FAKE (4.36)
|
||||
FSharp.Compiler.Service (2.0.0.6)
|
||||
FSharp.Core (4.0.0.1)
|
||||
FSharp.Formatting (2.14.4)
|
||||
FSharp.Compiler.Service (2.0.0.6)
|
||||
FSharpVSPowerTools.Core (>= 2.3 < 2.4)
|
||||
FSharp.Interop.Dynamic (3.0)
|
||||
Dynamitey (>= 1.0.2)
|
||||
FSharp.Core (>= 3.1.2.1)
|
||||
FSharpVSPowerTools.Core (2.3)
|
||||
FSharp.Compiler.Service (>= 2.0.0.3)
|
||||
Nancy (1.4.3)
|
||||
Nancy.Authentication.Forms (1.4.1)
|
||||
Nancy (>= 1.4.1)
|
||||
Nancy.Session.Persistable (0.9)
|
||||
Nancy (>= 1.4.3)
|
||||
Newtonsoft.Json (>= 9.0.1)
|
||||
Nancy.Session.RethinkDB (0.9)
|
||||
Nancy.Session.Persistable (>= 0.9)
|
||||
RethinkDb.Driver (>= 2.3.9)
|
||||
Newtonsoft.Json (9.0.1)
|
||||
NodaTime (1.3.2)
|
||||
RethinkDb.Driver (2.3.10)
|
||||
Common.Logging (>= 3.3) - framework: net45, net452
|
||||
Newtonsoft.Json (>= 9.0.1) - framework: net45, net452
|
||||
Suave (1.1.3)
|
||||
FSharp.Core (>= 3.1.2.5)
|
Loading…
Reference in New Issue
Block a user